今天简单聊聊Java中两个同步锁:synchronized 和ReentrantLock.
java同学肯定对synchronized这个关键字非常熟悉,通常会用在处理同步问题中。
首先,我们看一下synchronized常见的使用方式:
修饰实例方法 修饰类的静态方法 修饰代码块
使用方式
下面我们分别看一下三种方法的简单实现代码
修饰实例方法
public classtest {
private int sum = 0;
public synchronized voidaddNum() {
sum = sum + 1;
}
}
修饰实例方法时,锁对象为当前类的实例,不同的实例对象不会产生互斥效果。
修改类的静态方法
public classtest {
private static int num1 = 0;
public static synchronized voidaddSum(){
num1 = num1 + 1;
}
}
修改静态方法时,锁对象为当前类Class对象,即使不用线程中的不同的实例也会产生互斥效果。
修饰代码块
public classtest {
private Object lock = new Object();
public voidaddSum(){
synchronized (lock){
for (int i = 0; i < 10; i++) {
System.out.println("测试:"+i);
}
}
}
}
修饰代码块时,锁对象为synchronized后面括号中的对象,任何对象都可以作为锁对象。
接下来,我们看一下ReentrantLock的使用方式
public class Test {
ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Test tt = new Test();
Thread t1 = new Thread(newRunnable() {
@Override
public voidrun() {
tt.add();
}
});
Thread t2 = new Thread(newRunnable() {
@Override
public voidrun() {
tt.add();
}
});
t1.start();
t2.start();
}
public voidadd(){
try{
lock.lock();
for (int i = 0; i <10; i++) {
System.out.println("测试"+i);
}
}catch (Exception e){}
finally {
lock.unlock();
}
}
}
通过以上代码我们可以发现,不同于synchronized,ReentrantLock需要开发手动在代码中加锁和解锁。
在上述代码中,在finally方法中调用解锁unlock方法,是因为当异常发生时synchronized会自动的释放锁,但是ReentrantLokc并不会自动释放锁,所以放在finall代码块中,保证任何情况下锁都能被正常释放掉。
公平锁与非公平锁
公平锁:通过同步队列来实现多个线程按照申请锁的顺序获取锁。
默认情况下,synchronized和ReentrantLock都是非公平锁。但是ReentrantLock可以通过构造函数传参true,来创建公平锁,可以通过以下的部分源码。

两者的不同
1.锁的实现
synchronized是JVM虚拟机的实现, 而ReentrantLock是JDK实现的,是java.util.concurrent包中的锁。
2.性能
新版本java对synchronized进行了很多优化,引入许多概念,比如偏向锁,轻量锁,自旋锁等, 两者性能大致相同。
3.公平锁
上面文章已经提到了,此处省略。
4. 选择
ReentrantLock并不是所有的JDK版本都支持,除非需要使用ReentrantLock的高级功能,否则优先选择使用synchronized。因为这是JVM内置实现的一种锁机制,原生支持,不用担心没有释放锁导致的死锁问题,因为JVM会确保锁的释放。
单例的双重校验锁实现(面试必备)
public class Singleton {
privateSingleton() {}
// 使用volatile修饰变量可以禁止JVM的指令重排,保证多线程下获取实例的唯一。
private volatile static Singleton instance;
public static SingletongetInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
synchronized底层实现原理
synchronized是采用对象内部监视器(ObjectMonitor)的同步机制,是基于JVM对操作系统底层的Mutex Lock(互斥锁)实现的,期间会由用户态转入操作系统内核态。synchronized实现锁,是一个重量锁,当多个线程切换上下文时,是非常重量级的操作,成本非常高。