一.概述
- java1.5为我们提供了同步控制的新途径, java.util.concurrent.locks.*提供了两个核心接口:Lock,Condition。
- Lock接口提供了比synchronized关键字同步流程更加清晰的方法。
- Condition接口替代了object对象的三个监视方法。
二.代码
- 传统synchronized + wait + notify控制同步。
package com.zzy.syn; /** * 传统同步方式 * synchronized + wait + notify * @author eason * */ public class TestSynchronized { public static void main(String[] args) { final Service service = new Service(); new Thread(new Runnable() { @Override public void run() { service.subThread(); //新线程调用subThread方法 } }).start(); service.mainThread(); //主线程调用mainThread方法 } static class Service { private boolean shouldSubRun = true; //此时是否该执行subThread方法 public synchronized void mainThread() { while(shouldSubRun) { try { wait(); //该执行subThread方法,调用mainThread方法的主线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("mainThread method execute"); //逻辑区域 shouldSubRun = true; //mainThread方法执行完后,该执行subThread方法 notify(); //唤醒等待在subThread方法上的的新线程 } public synchronized void subThread() { while(!shouldSubRun) { try { wait(); //该执行mainThread方法,调用subThread方法的新线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("subThread method execute"); //逻辑区域 shouldSubRun = false; //subThread方法执行完后,该执行mainThread方法 notify(); //唤醒等待在mainThread方法上的的主线程 } } }
- Lock+Condition控制同步。
package com.zzy.syn; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * java1.5提供的同步方式 * lock + condition * @author eason * */ public class TestLock { public static void main(String[] args) { final Service service = new Service(); //线程sub1调用service的sub1方法 new Thread(new Runnable() { @Override public void run() { service.sub1(); } }, "sub1").start(); //线程sub2调用service的sub2方法 new Thread(new Runnable() { @Override public void run() { service.sub2(); } }, "sub2").start(); //线程sub3调用service的sub31方法 new Thread(new Runnable() { @Override public void run() { service.sub3(); } }, "sub3").start(); } static class Service { private int shouldSubNum = 1; //此时该sub几方法执行 private Lock lock = new ReentrantLock(); Condition sub1 = lock.newCondition(); Condition sub2 = lock.newCondition(); Condition sub3 = lock.newCondition(); public void sub1() { lock.lock(); try{ while(shouldSubNum != 1) { try { sub1.await(); //该sub2或sub3方法执行时,调用sub1方法的sub1线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("sub1 method execute"); shouldSubNum = 3; //sub1方法线程完后,轮到sub3执行 sub3.signal(); //唤醒调用sub3方法的sub3线程 } finally { lock.unlock(); } } public void sub2() { lock.lock(); try{ while(shouldSubNum != 2) { try { sub2.await(); //该sub1或sub3方法执行时,调用sub2方法的sub2线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("sub2 method execute"); shouldSubNum = 1; //sub2方法线程完后,轮到sub1执行 sub1.signal(); //唤醒调用sub1方法的sub1线程 } finally { lock.unlock(); } } public void sub3() { lock.lock(); try{ while(shouldSubNum != 3) { try { sub3.await(); //该sub1或sub2方法执行时,调用sub3方法的sub3线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("sub3 method execute"); shouldSubNum = 2; //sub3方法线程完后,轮到sub2执行 sub2.signal(); //唤醒调用sub2方法的sub2线程 } finally { lock.unlock(); } } } }
三.二者对比
- Lock接口提供了比synchronized更加广泛和灵活的操作。
- Lock接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁。上例一个反应出来了。
- 其他的用到在写。
- synchronized是在JVM 层面上实现的,Lock是在代码层面实现的。
- synchronized在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。