并发问题:
1、synchronized关键字
双重校验锁实现对象单例
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
在代码中uniqueInstance采用volatile关键字修饰,目的是为了禁止JVM的重排序。
这段代码的执行过程为:
1、为uniqueInstance分配内存空间
2、初始化uniqueInstance
3、将uniqueInstance指向分配的内存地址
在JVM中具有指令重排的特性,执行顺序可能变为1->3->2,指令重排在单线程环境下不会出问题,但在多线程环境下会导致一个线程获得还没初始化的实例。
例如T1执行了1和3,此时T2调用了getUniqueInstance()发现uniqueInstance不为空,因此返回uniqueInstance,但此时uniqueInstance还未被初始化。
使用volatile可以禁止JVM的指令重排,保证多线程的环境下也能正常运行。
2、synchronized关键字的底层原理
synchronized同步语句块实现使用的是monitorenter和monitorexit指令,其中
monitorenter指向同步代码块的开始位置,monitorexit指向同步代码块的结束位置。
synchronized修饰的方法并没有monitorenter和monitorexit指令,取而代之的是ACC_SYNCHONIZED标识,该标识指明了该方法是一个同步方法,JVM通过该ACC_SYNCHONIZED访问标志来辨别一个方法是否为同步方法,从而执行相应的同步调用。
3、谈谈synchronized和ReentrantLock的区别?
1、两者都可重入锁。可重入锁的概念是:自己可以再次获取自己的内部锁。
2、synchrnonized依赖于JVM而ReentrantLock依赖于API。ReentrantLock依赖于JDK层面实现的,需要lock()和unlock()方法配合try/finally语句块来完成。
3、ReentrantLock比synchronized增加了一些高级功能。高级功能主要有三点:等待可中断、可实现公平锁、可实现选择性通知
5、volatile关键字
volatile关键字的作用是:保证变量的可见性,在变量钱加volatile关键字就是指示JVM这个变量不稳定,每次使用它都到主存中读取。
还有一个作用是防止指令重排序。