synchronized和lock的区别
先简单了解一下sync的使用场景
1.原始构造
sync是关键字属于JVM层面
monitorenter(底层是通过monitor对象来完成,其实wait/notify等方法也依赖于monitor对象只有在同步块和方法中才能调用wait/notify等方法)
monitorexit
Lock是具体的类(java.util.concurrent.locks.Lock)是api层面的锁
编译后的字节码:
2.使用方法
sync不需要用户手动释放,当代码执行完系统会自动释放对所的占用
ReenTrantLock则需要用户手动释放,不释放就会造成死锁
需要lock()和unlock()方法配合使用
3.等待是否可中断
sync是不可以中断的,除非抛出异常或者正常执行完成
ReenTrantLock可中断:
1.设置超时方法,tryLock(long time, TimeUnit unit) 类似于你去上厕所,里面有个人在刷抖音,你等了三分钟,里面的人还没出来,你心想算了,就走了。
2.lockInterruptibly() 放在代码块中,调用interrupted()方法可中断
4.加锁是否公平
sync默认非公平锁
ReenTrantLock默认也是非公平锁,构造方法可以传入boolean值,true为公平锁,false为非公平锁
5.线程唤醒
sync没有condition,要么随机唤醒一个线程notify(),要么全部唤醒notifyAll()
ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒。
condition线程唤醒代码案例:
AA、BBx线程先启动,AA、BB 进入休眠状态,CC启动并尝试唤醒AA线程,AA线程唤醒成功后尝试唤醒BB线程
/*
* Copyright (C), 2013-2019, 天津大海云科技有限公司
*/
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 测试conditon唤醒指定线程
*
* @author yangjikang
* @date 2019/6/18 11:58
* @modified By yangjikang
*/
public class TestCondition {
public static void main(String[] args) {
Lock lock = new ReentrantLock(true);
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "\t 线程启动...");
condition1.await();
System.out.println(Thread.currentThread().getName() + "\t 线程被唤醒...3秒后开始唤醒BB线程...");
TimeUnit.SECONDS.sleep(3);
condition2.signal();
System.out.println(Thread.currentThread().getName() + "\t 线程结束...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "AA").start();
new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "\t 线程启动...");
condition2.await();
System.out.println(Thread.currentThread().getName() + "\t 线程被唤醒...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "BB").start();
new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "\t 线程启动...尝试5秒后唤醒AA线程...");
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName() + "\t 线程结束...开始唤醒AA线程...");
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "CC").start();
}
}
控制台效果图