synchronized 解决的是多个线程访问资源的同步性问题,synchronized 可以保证被它修饰的方法或者代码块在同一时间只有一个线程可以执行。
synchronized void method() {
//业务代码
}
synchronized void staic method() {
//业务代码
}
synchronized(this) {
//业务代码
}
/**
* @author LanceQ
* @version 1.0 2021/4/11
*/
public class SingletonDemo {
//禁止指令重排volatile
private static volatile SingletonDemo instance=null;
// private static SingletonDemo instance=null;
private SingletonDemo(){
System.out.println(Thread.currentThread().getName()+"\t 我是构造方法SingleDemo()");
}
//DCL(double check lock双端检锁机制)
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class){
if(instance==null)
instance = new SingletonDemo();
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i <20; i++) {
new Thread(()->{
SingletonDemo.getInstance();
},String.valueOf(i)).start();
}
}
}
但是由于 JVM 具有指令重排的特性,执⾏顺序有可能变成 1->3->2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致⼀个线程获得还没有初始化的实例。
例如,线程 T1 执⾏了 1 和 3,此时 T2 调⽤ getInstance() 后发现 instance 不为空,因此返回instance,但此时 instance 还未被初始化。
使⽤ volatile 可以禁⽌ JVM 的指令重排,保证在多线程环境下也能正常运⾏。
synchronized 同步语句块的实现使⽤的是 monitorenter 和 monitorexit 指令,其中monitorenter 指令指向同步代码块的开始位置, monitorexit 指令则指明同步代码块的结束位置。
synchronized 修饰的⽅法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是ACC_SYNCHRONIZED 标识,该标识指明了该⽅法是⼀个同步⽅法。
参考:JavaGuide面试突击版
因篇幅问题不能全部显示,请点此查看更多更全内容