Lock、ReentrantLock、Synchronized有什么区别?使用新的Lock有什么好处?
-
Synchronized
是 JVM层面,是Java的关键字。
monitorenter/monitorexit(底层是通过monitor对象来完成,其实wait/notify等方法也依赖于monitor对象,只有在同步块或方法中才能调用wait/notify等方法)
Lock
是Java.util.concurrent.locks包下的一个接口,一个具体的类。
-
synchronized
不需要用户手动释放锁,当synchronized
代码执行完成后系统会自动让线程释放对锁的占用
ReentrantLock
则需要用户手动释放锁,若没有主动释放锁,就有可能出现死锁情况。
-
synchronized
不可中断,除非抛出异常,或者正常完成运行。
ReentrantLock
可以中断
3.1 设置超时方法trylock(long timeout, TimeUnit unit)
3.2 lockInterruptibly()
放代码块中,调用interrup()
方法可以中断。
- 加锁是否公平
Synchronized
:非公平锁
ReentrantLock
:两者都可以,默认是非公平锁。
- 锁绑定多个条件Condition
Synchronized
:没有
ReentrantLock
:用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像Synchronized
一样,要么随机唤醒一个线程,要么唤醒全部线程。
Lock_Condition实例题目
- 多线程按顺序调用,实现ABC三个线程启动,要求如下:
A打印5次,通知B打印10次,通知C打印15次
紧接着,通知A打印5次,通知B打印10次,通知C打印15次
重复十轮。
package com.company;
import javax.swing.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ShareResource{
private volatile int number = 1;//A:1,B:2,C:3
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
//判断
public void print(){
lock.lock();
try{
//1 判断
while(number != 1)
{
c1.await();
}
//干活
for (int i = 1; i <= 5; i++)
{
System.out.println(Thread.currentThread().getName()+"\t work");
}
//通知
number = 2;//修改标志位
c2.signal();//单独通知2号线程
}catch(Exception e){
e.printStackTrace();
}finally {
lock.lock();
}
};
public void print10(){
lock.lock();
try{
//1 判断
while(number != 2)
{
c2.await();
}
//干活
for (int i = 1; i <= 10; i++)
{
System.out.println(Thread.currentThread().getName()+"\t work");
}
//通知
number = 3;//修改标志位
c3.signal();//单独通知3号线程
}catch(Exception e){
e.printStackTrace();
}finally {
lock.lock();
}
};
public void print15(){
lock.lock();
try{
//1 判断
while(number != 3)
{
c3.await();
}
//干活
for (int i = 1; i <= 15; i++)
{
System.out.println(Thread.currentThread().getName()+"\t work");
}
//通知
number = 1;//修改标志位
c1.signal();//单独通知1号线程
}catch(Exception e){
e.printStackTrace();
}finally {
lock.lock();
}
};
}
/**
* 多线程按顺序调用,实现ABC三个线程启动,要求如下:
* A打印5次,B打印10次,C打印15次
* 紧接着,A打印5次,B打印10次,C打印15次
* 重复十轮。
*/
public class ConditionDemo {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(()->{
for (int i = 1; i <= 10; i++) {
shareResource.print();
}
},"A").start();
new Thread(()->{
for (int i = 1; i <= 10; i++) {
shareResource.print10();
}
},"B").start();
new Thread(()->{
for (int i = 1; i <= 10; i++) {
shareResource.print15();
}
},"C").start();
}
}