1.原始构成
(1).Syschronized是关键字,属于JVM层面。底层是通过monitor对象来完成。monitorenter:进入;monitorexit:退出。其实wait/notigy等方法也依赖monitor对象,只有在同步块或方法中才能调wait/notify等方法。
(2).Lock是具体类(java.util.concurrent.locks.Lock)是api层面的锁。
2.使用方法
(1).Synchronized 不需要用户去手动释放锁,当synchronied代码执行完后系统会自动让线程释放对锁的占用。
(2).ReentrantLock则需要用户去手动释放锁若没有主动释放锁,就有可能导致出现死锁现象。
3.等待是否可中断
(1).synchronized不可中断,除非抛出异常或者正常运行完成。
(2).ReentrantLock 可中断。可通过 设置超时方法 tryLock(long timeout,TimeUnit unit) 或 调用interrupt()方法可中断。
4.加锁是否公平
(1).synchronized 非公平锁
(2).ReentrantLock两者都可以,默认非公平锁,构造方法可以传入boolean值,true为公平锁,false为非公平锁。
5. 锁绑定多个条件Condition
(1).synchronized没有
(2).ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。Java代码示例如下:
/**
* 资源类
*/
class Resource {
private int number = 1; //A:1 B:2
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
public void print(String var) throws Exception{
lock.lock();
try{
if("A" == var){
// 1 判断
while (number != 1){
condition1.await();
}
// 打印A
System.out.println(Thread.currentThread().getName()+"\tA"+number);
// 3 通知唤醒
number = 2;
condition2.signalAll();
}else if("B" == var){
while (number != 2){
condition2.await();
}
// 打印B
System.out.println(Thread.currentThread().getName()+"\tB"+number);
// 3 通知唤醒
number = 1;
condition2.signalAll();
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
/**
* @author Runner
*
* 锁绑定多个条件Condition,此示例代码实现打印完A后再打印B,然后再打印A,按此顺序循环5次
*/
public class Test {
public static void main(String[] arg) throws InterruptedException {
Resource resource = new Resource();
new Thread(() ->{
try {
for (int i = 1; i <=5 ; i++) {
resource.print("A");
}
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
new Thread(() ->{
try {
for (int i = 1; i <=5 ; i++) {
resource.print("B");
}
} catch (Exception e) {
e.printStackTrace();
}
},"B").start();
}
}