目前在Java中存在两种锁机制:Synchronized和Lock,Lock接口及其实现类是JDK1.5增加的内容。本文将从不同角度分析两者的区别。
1. 原始构成
Synchronized 是关键字属于JVM层面 monitorenter(底层是通过monitor对象来完成,其实wait/notify等方法也依赖monitor对象,只有在同步块或方法中才能掉wait/notify等方法) monitorexitLock 是具体的类,是API层面的锁2. 使用方法
Synchronized 不需要用户手动释放锁,当Synchronized 代码执行完后系统会自动让线程释放对锁的占用Lock ReentrantLock则需要用户去手动释放锁,若没有主动释放锁,就有可能出现死锁现象 需要lock()和unlock()方法配合try/finally语句块完成3. 等待是否可中断
Synchronized 不可中断,除非抛出异常或正常运行结束
Lock ReentrantLock可中断:
设置超时方法tryLock(long timeout, TimeUnit unit)locInterruptibly()放代码块中,调用interrupt()方法可中断4. 加锁是否公平
Synchronized 非公平锁
Lock ReentrantLock两者都可以,默认非公平锁构造方法可以传入Boolean值,true为公平,false为非公平锁
5. 锁绑定多个条件Condition
Synchronized 没有
Lock ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像Synchronized 要么随机唤醒一个线程要么唤醒全部线程
多线程之间按顺序调用,实现A->B->C三个线程启动,要求如下: AA打印5次,BB打印10次,CC打印15次 。。。 AA打印5次,BB打印10次,CC打印15次 一共循环打印10轮
public class SynLockDemo { public static void main(String[] args) { Resource resource = new Resource(); new Thread(() -> { for (int i = 0; i < 10; i++) { resource.print5(); } },"A" ).start(); new Thread(() -> { for (int i = 0; i < 10; i++) { resource.print10(); } },"B" ).start(); new Thread(() -> { for (int i = 0; i < 10; i++) { resource.print15(); } },"C" ).start(); } } class Resource{// 资源类 private int num = 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 print5(){ lock.lock(); try { //1.判断 while (num!=1){ c1.await(); } //2.干活 for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+"\t"+i); } //3.通知 num = 2; c2.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void print10(){ lock.lock(); try { //1.判断 while (num != 2){ c2.await(); } //2.干活 for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"\t"+i); } //3.通知 num = 3; c3.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void print15(){ lock.lock(); try { //1.判断 while (num != 3){ c3.await(); } //2.干活 for (int i = 0; i < 15; i++) { System.out.println(Thread.currentThread().getName()+"\t"+i); } //3.通知 num = 1; c1.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } }