以上是核心的關於CountDownLatch、ReentrantLock的分析。因爲博主研究程度有限,想更深層次研究,請參考:Java併發AQS詳解html
/** * CountDownLatch至關於指令槍或者門閂,全部線程都awit()阻塞在起跑線,只有countDown到state爲0,其餘線程才能往下運行。 * @author qiuyongAaron */ public class CountDownLatchDemo { private static final int PLAYER_NUM=5; public static void main(String[] args) { CountDownLatch start=new CountDownLatch(1); CountDownLatch end =new CountDownLatch(PLAYER_NUM); Player [] players=new Player[PLAYER_NUM]; for(int i=0;i<PLAYER_NUM;i++) players[i]=new Player(start, end, i); //指定線程個數的線程池! ExecutorService exe=Executors.newFixedThreadPool(PLAYER_NUM); for(Player player:players) exe.execute(player); System.out.println("比賽開始!"); //比賽開始! start.countDown(); try { end.await(); } catch (InterruptedException e) { e.printStackTrace(); }finally{ System.out.println("比賽結束!"); exe.shutdown(); } } } class Player implements Runnable{ private CountDownLatch start; private CountDownLatch end; private int id; Random random=new Random(); public Player(CountDownLatch start,CountDownLatch end,int id) { this.start=start; this.end=end; this.id=id; } @Override public void run() { try { //等待比賽開始。 start.await(); TimeUnit.SECONDS.sleep(random.nextInt(10)); System.out.println("Player-"+id+":arrived"); } catch (InterruptedException e) { e.printStackTrace(); }finally{ //選手-id到達終點,end計數爲0結束比賽! end.countDown(); } } } //運行結果: 比賽開始! Player-3:arrived Player-4:arrived Player-0:arrived Player-1:arrived Player-2:arrived 比賽結束!
/** * 示例一:同步鎖的使用 * reentrantlock用於替代synchronized * 本例中因爲m1鎖定this,只有m1執行完畢的時候,m2才能執行 * @author qiuyongAaron */ public class ReentrantLockOne { public synchronized void m1(){ for(int i=0;i<10;i++){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } } public synchronized void m2(){ System.out.println("hello m2!"); } public static void main(String[] args) { ReentrantLockOne lock=new ReentrantLockOne(); new Thread(()->lock.m1(),"t1").start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->lock.m2(),"t2").start(); } }
2.2 ReentrantLock實現線程同步-與synchronized做用一致!編程
/** * 示例二:等價於同步鎖 * 使用reentrantlock能夠完成一樣的功能 * 須要注意的是,必需要必需要必需要手動釋放鎖(重要的事情說三遍) * 使用syn鎖定的話若是遇到異常,jvm會自動釋放鎖,可是lock必須手動釋放鎖,所以常常在finally中進行鎖的釋放 * @author qiuyongAaron */ public class ReentrantLockTwo { ReentrantLock lock =new ReentrantLock(); public void m1(){ try { lock.lock(); for(int i=0;i<10;i++){ TimeUnit.SECONDS.sleep(1); System.out.println(i); } } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } } public synchronized void m2(){ lock.lock(); System.out.println("hello m2!"); lock.unlock(); } public static void main(String[] args) { ReentrantLockTwo lock=new ReentrantLockTwo(); new Thread(()->lock.m1(),"t1").start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->lock.m2(),"t2").start(); } }
/** * 示例三:tryLock * 使用reentrantlock能夠進行「嘗試鎖定」tryLock,這樣沒法鎖定,或者在指定時間內沒法鎖定,線程能夠決定是否繼續等待 * @author qiuyongAaron */ public class ReentrantLockThree { ReentrantLock lock=new ReentrantLock(); public void m1(){ try { lock.lock(); for(int i=0;i<10;i++){ TimeUnit.SECONDS.sleep(1); System.out.println(i); } } catch (Exception e) { e.printStackTrace(); }finally{ lock.unlock(); } } boolean locked=false; public void m2(){ try { lock.tryLock(5,TimeUnit.SECONDS); System.out.println("m2:"+locked); } catch (Exception e) { e.printStackTrace(); }finally{ if(locked) lock.unlock(); } } public static void main(String[] args) { ReentrantLockThree lock=new ReentrantLockThree(); new Thread(()->lock.m1(),"t1").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->lock.m2(),"t2").start(); } }
2.4 指定公平鎖或者搶佔式鎖數組
/** * ReentrantLock還能夠指定爲公平鎖 * @author qiuyongAaron */ public class ReentrantLockFive extends Thread{ //默認false:爲非公平鎖 true:公平鎖 ReentrantLock lock=new ReentrantLock(); @Override public void run() { for(int i=0;i<100;i++){ lock.lock(); try { TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+"得到鎖"+"-"+i); } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } } } public static void main(String[] args) { ReentrantLockFive lock=new ReentrantLockFive(); new Thread(lock,"t1").start(); new Thread(lock,"t2").start(); } } 運行結果: //非公平鎖 t2得到鎖-0 t2得到鎖-1 t1得到鎖-0 t1得到鎖-1 t1得到鎖-2 t2得到鎖-2 //公平鎖 t1得到鎖-0 t2得到鎖-0 t1得到鎖-1 t2得到鎖-1 t1得到鎖-2 t2得到鎖-2
/** * 模擬生產者消費者模式-線程之間通訊 synchronized-notifyAll/wait * @author qiuyongAaron */ public class MyContainerOne { LinkedList<Integer> list=new LinkedList<Integer>(); static final int MAX=10; int count=0; //生產者線程 public synchronized void put(int i){ while(list.size()==MAX){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } list.add(i); ++count; this.notifyAll();//通知消費者來消費 } //消費者線程 public synchronized int get(){ while(list.size()==0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int num=list.removeFirst(); count--; this.notifyAll();//通知生產者生產 return num; } public static void main(String[] args) { MyContainerOne container=new MyContainerOne(); //製造10個消費者 for(int i=0;i<10;i++){ new Thread(()->{ for(int j=0;j<5;j++) System.out.println(container.get()); }, "c"+i).start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } //製造2個生產者 for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<25;j++) container.put(j); }, "p"+i).start(); } } }
/** * 模擬生產者消費者模式-reentrantLock-awit/signAll * @author qiuyongAaron */ public class MyContainerTwo { LinkedList<Integer> list=new LinkedList<Integer>(); static final int MAX=10; int count=0; ReentrantLock lock=new ReentrantLock(); Condition producer=lock.newCondition(); Condition consumer=lock.newCondition(); //生產者線程 public void put(int i){ try { lock.lock(); while(list.size()==MAX){ producer.await(); } list.add(i); ++count; consumer.signalAll();//通知消費者來消費 } catch (InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock(); } } //消費者線程 public int get(){ try{ lock.lock(); while(list.size()==0){ consumer.await(); } int num=list.removeFirst(); count--; producer.signalAll();//通知生產者生產 return num; }catch(Exception e){ e.printStackTrace(); }finally{ lock.unlock(); } return 0; } public static void main(String[] args) { MyContainerTwo container=new MyContainerTwo(); //製造10個消費者 for(int i=0;i<10;i++){ new Thread(()->{ for(int j=0;j<5;j++) System.out.println(container.get()); }, "c"+i).start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } //製造2個生產者 for(int i=0;i<2;i++){ new Thread(()->{ for(int j=0;j<25;j++) container.put(j); }, "p"+i).start(); } } }
做者:邱勇Aaron安全
出處:http://www.cnblogs.com/qiuyong/多線程
您的支持是對博主深刻思考總結的最大鼓勵。併發
本文版權歸做者全部,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,尊重做者的勞動成果。dom
參考:馬士兵併發編程、併發編程實踐jvm
AQS詳解:http://www.cnblogs.com/waterystone/p/4920797.htmlide