synchronized和ReentrantLock的区别
- synchronized是一个关键字,是JVM内部实现的;ReentrantLock是标准库的一个类,是JVM外部基于Java实现的。
- synchronized在申请锁失败时会死等;ReentrantLock可以通过tryLock的方式等待一段时间就放弃。
- synchronized使用时不需要手动释放锁;ReentrantLock使用时需要手动释放锁,它更加灵活,但是容易忘记unlock。
- synchronized是一个非公平锁;ReentrantLock默认是非公平锁,但它可以通过在构造方法中传入一个true开启公平锁模式。
- ReentrantLock的唤醒机制比synchronized更加强大,synchronized是通过Object类的wait/notify实现等待-唤醒,且每次唤醒的是一个随机等待的线程;ReentrantLock搭配Condition类实现等待-唤醒,可以更加精确的控制唤醒某个指定的线程。
三个线程交替打印ABC案例(ReentrantLock搭配Condition展现的指定唤醒功能):
//交替打印ABC ReentrantLock
/**
* loker.lock()放在try的第一行或者try的外面!!!
*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Demo_4 {
static ReentrantLock loker = new ReentrantLock();
static Condition A = loker.newCondition();
static Condition B = loker.newCondition();
static Condition C = loker.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
loker.lock();
for (int i = 0; i < 10; i++) {
A.await();//等待其他线程唤醒
B.signal();//唤醒线程
System.out.println("A");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
loker.unlock();
}
});
Thread t2 = new Thread(() -> {
try {
loker.lock();
for (int i = 0; i < 10; i++) {
B.await();//等待其他线程唤醒
C.signal();//唤醒线程
System.out.println("B");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
loker.unlock();
}
});
Thread t3 = new Thread(() -> {
try {
loker.lock();
for (int i = 0; i < 10; i++) {
C.await();//等待其他线程唤醒
A.signal();//唤醒线程
System.out.println("C");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
loker.unlock();
}
});
//上面线程循环
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);//确保线程都启动
//从A切入启动线程
try {
loker.lock();
A.signal();
} finally {
loker.unlock();
}
}
}
- synchronized是基于操作系统的mutex锁实现的;ReentrantLock是基于CAS和AQS实现的。