Java多線程與並發庫高級應用-工具類介紹


java.util.concurrent.Lock

1、Lock比傳統線程模型中的synchronized方式更加面向對象,與生活中的鎖類似,
鎖本身也應該是一個對象。兩個線程執行的代碼片段要實現同步互斥的效果,它們必須用同一個Lock對象。

  lock替代synchronized

  

class Outputer { Lock lock = new ReentrantLock(); public void output(String name) { int len = name.length(); lock.lock(); try{ for (int i = 0; i < len; i++) { char c = name.charAt(i); System.out.print(c); } }finally{ lock.unlock(); //這里防止內部代碼出現異常,即無論如何最后都會釋放鎖
 } lock.unlock(); System.out.println(); } }

 

售票系統

package com.java.juc;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(ticket, "窗口1售票").start();
        new Thread(ticket, "窗口2售票").start();
        new Thread(ticket, "窗口3售票").start();
    }

}

class Ticket implements Runnable {
    private int ticket = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                if (ticket > 0) {
                    Thread.sleep(20);
                    System.out.println(Thread.currentThread().getName()
                            + ",余票量:" + ticket--);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

 

 

 

2、讀寫鎖:

讀寫鎖:分為讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,這是由jvm自己控制的,你只要上好相應的鎖即可。
* 如果你的代碼只讀數據,可以很多人同時讀,但不能同時寫,那就上讀鎖;
* 如果你的代碼修改數據,只能有一個人在寫,且不能同時讀取,那就上寫鎖。
* 總之,讀的時候上讀鎖,寫的時候上寫鎖!

/* 面試題:3個線程讀,3個線程寫 同一個數據 */
public class ReadWriteLockTest { public static void main(String[] args) { final Queue3 queue = new Queue3(); for(int i = 0;i<3;i++){ new Thread(new Runnable() { @Override public void run() { while(true){ queue.get(); } } }).start(); new Thread(new Runnable() { @Override public void run() { queue.set(new Random().nextInt(10000)); } }).start(); } } } class Queue3{ private Object data = null; //共享數據 ,只能有一個線程寫該數據,但可以有多個線程同時讀
    ReadWriteLock rwl = new ReentrantReadWriteLock();  //讀寫鎖
    
    public void get(){ try { rwl.readLock().lock(); //上讀鎖 可以有多個線程同時讀
            System.out.println(Thread.currentThread().getName() + " be ready to read data!"); Thread.sleep((long)Math.random() * 1000); System.out.println(Thread.currentThread().getName() + " have read data : "+ data); } catch (InterruptedException e) { }finally{ rwl.readLock().unlock(); //釋放讀鎖
 } } public void set(Object data){ try { rwl.writeLock().lock(); //添加寫鎖,保證只能有一個線程進行寫操作
            System.out.println(Thread.currentThread().getName() + " be read to write data: "+ data); Thread.sleep((long)Math.random() * 1000); this.data = data; System.out.println(Thread.currentThread().getName() + "has write data"); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.writeLock().unlock(); //釋放寫鎖
 } } }

 簡單的讀寫鎖示例

package com.java.juc;

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestReadWriteLock {
    public static void main(String[] args) {
        final ReadWriteLockDemo demo = new ReadWriteLockDemo();
        new Thread(new Runnable(){
            @Override
            public void run() {
                demo.set(new Random().nextInt(5000));
            }
        },"Write").start();
        
        for(int i = 0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    demo.get();
                }
            }, "Read").start();
        }
    }
}

class ReadWriteLockDemo{
    private int number = 0;
    
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    
    public void get(){
        try{
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName() +" "+number);
        }finally{
            lock.readLock().unlock();
        }
    }
    public void set(int number){
        try{
            lock.writeLock().lock();
            this.number = number;
        }finally{
            lock.writeLock().unlock();
        }
    }
}

 

 

 Hibernate的一個面試題:

  User user = session.load(id,User.class);

  User user = session.get(id,User.class);

  以上兩個的卻別。

  get()方式,直接查詢數據庫,如果查詢到賦值給User對象,如果沒有查詢到則返回為null

  load()方式,實際上是從User的一個代理中獲取, User$Proxy中包含有一個真實的User對象,當調用load()時,如果成員變量User為null,則從數據庫查詢將記錄返回並給User賦值,當load()時User不為null,則直接返回User對象

 

/** * 面試題: 設計一個緩存系統 * @author Administrator * */
public class CacheDemo { Map<String, Object> cache = new HashMap<String, Object>(); public static void main(String[] args) { } private ReadWriteLock rwl = new ReentrantReadWriteLock(); public Object getData(String key){ rwl.readLock().lock(); Object value = null; try { value = cache.get(key); if(value == null){ rwl.readLock().unlock(); rwl.writeLock().lock(); try { if(value == null){ //防止后邊線程加載數據,使用雙端檢測機制 value = "xxx"; //queryDB
 cache.put(key, value); } }finally{ rwl.writeLock().unlock(); } rwl.readLock().lock(); } } catch (Exception e) { }finally{ rwl.readLock().unlock(); } return value; } }

 

 

ReadWriteLock javaAPI中有緩存的代碼:

class CachedData {
   Object data;
   volatile boolean cacheValid;
   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // Must release read lock before acquiring write lock
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        // Recheck state because another thread might have acquired
        //   write lock and changed state before we did.
        if (!cacheValid) {
          data = ...
          cacheValid = true;
        }
        // Downgrade by acquiring read lock before releasing write lock
        rwl.readLock().lock();
        rwl.writeLock().unlock(); // Unlock write, still hold read
     }

     use(data);
     rwl.readLock().unlock();
   }
 }

 

3、Condition 實現線程通信

傳統的線程通信方式

/* * 傳統線程通信 * 主線程和子線程分別打印 100次 和 10次,循環50次 */
public class TraditionalThreadCommunication2 { public static void main(String[] args) { final Buiness buiness = new Buiness(); new Thread(new Runnable() { @Override public void run() { for(int i = 1;i<=50;i++){ buiness.sub(i); } } }).start(); for(int i = 1;i<=50;i++){ buiness.main(i); } } static class Buiness{ private boolean isShouldSub = false;  //主線程先打印
        public synchronized void main(int j){ //進行同步,防止在打印時被其他線程干擾
            while(isShouldSub){  //這里使用while 防止假喚醒
                try { this.wait();  //wait() 和 notify() 必須出現在synchronized同步中
                } catch (InterruptedException e) { e.printStackTrace(); } } for(int i = 1;i<=100;i++){ System.out.println("main thread print "+ i + " loop of " + j); } isShouldSub = true; this.notify(); } public synchronized void sub(int j){ while(!isShouldSub){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i = 1 ; i<=10;i++){ System.out.println("sub thread print "+ i + " loop of " + j); } isShouldSub = false; this.notify(); } } }

 

 

將上述程序改寫為使用Condition

/* * 傳統線程通信 * 主線程和子線程分別打印 100次 和 10次,循環50次 * 改寫成使用 Condition 的方式 */
public class TraditionalThreadCommunication2 { public static void main(String[] args) { final Buiness buiness = new Buiness(); new Thread(new Runnable() { @Override public void run() { for(int i = 1;i<=50;i++){ buiness.sub(i); } } }).start(); for(int i = 1;i<=50;i++){ buiness.main(i); } } /** * 將程序改寫為使用Lock&Condition的方式進行 同步和通信 * @author Administrator * */
    static class Buiness{ Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); private boolean isShouldSub = false;  //主線程先打印
        public void main(int j){ //進行同步,防止在打印時被其他線程干擾
 lock.lock(); try { while(isShouldSub){  //這里使用while 防止假喚醒
                    try { condition.await(); // this.wait(); //wait() 和 notify() 必須出現在同步監視器內部中
                    } catch (Exception e) { e.printStackTrace(); } } for(int i = 1;i<=100;i++){ System.out.println("main thread print "+ i + " loop of " + j); } isShouldSub = true; condition.signal(); // this.notify(); 
            } finally { lock.unlock(); } } public void sub(int j){ lock.lock(); try { while(!isShouldSub){ try { condition.await(); // this.wait();
                    } catch (Exception e) { e.printStackTrace(); } } for(int i = 1 ; i<=10;i++){ System.out.println("sub thread print "+ i + " loop of " + j); } isShouldSub = false; condition.signal(); // this.notify();
            } finally{ lock.unlock(); } } } }

main thread print 1 loop of 1
main thread print 2 loop of 1
main thread print 3 loop of 1
main thread print 4 loop of 1
main thread print 5 loop of 1
main thread print 6 loop of 1
main thread print 7 loop of 1
...
main thread print 99 loop of 1
main thread print 100 loop of 1
sub thread print 1 loop of 1
sub thread print 2 loop of 1
sub thread print 3 loop of 1
sub thread print 4 loop of 1
sub thread print 5 loop of 1
sub thread print 6 loop of 1
sub thread print 7 loop of 1
sub thread print 8 loop of 1
sub thread print 9 loop of 1
sub thread print 10 loop of 1
main thread print 1 loop of 2
main thread print 2 loop of 2
main thread print 3 loop of 2
main thread print 4 loop of 2
main thread print 5 loop of 2
main thread print 6 loop of 2
main thread print 7 loop of 2
main thread print 8 loop of 2
main thread print 9 loop of 2
...
main thread print 99 loop of 2
main thread print 100 loop of 2
sub thread print 1 loop of 2
sub thread print 2 loop of 2
sub thread print 3 loop of 2
sub thread print 4 loop of 2
sub thread print 5 loop of 2
sub thread print 6 loop of 2
sub thread print 7 loop of 2
sub thread print 8 loop of 2
sub thread print 9 loop of 2
sub thread print 10 loop of 2
main thread print 1 loop of 3
main thread print 2 loop of 3
main thread print 3 loop of 3

...

 

使用Condition比傳統的好處

可以實現多路Condition ,在javaAPI中有

class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }
 }

使用多路Condition,可以擴展上述的一個例子,老大打印完 -> 老二   老二-> 老三  老三-> 老大  老大-> 老二...

 

/** * 第一個線程循環100次,第二個線程循環10次,第三個線程循環20次,如此循環50次,請寫出程序 這里使用Condition * * @author Administrator * */
public class ThreeConditionCommunication { public static void main(String[] args) { final Business2 business = new Business2(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { business.sub2(i); } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { business.sub3(i); } } }).start(); for (int i = 1; i <= 50; i++) { business.main(i); } } } class Business2 { Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); private int shoudeSub = 1; public void sub2(int i) { lock.lock(); try { while (shoudeSub != 2) { // 這里也可以用 if ,用while比較好一些 As in the one argument // version, interrupts and spurious wakeups are // possible, and this method should always be // used in a loop
                try { // 防止線程有可能被假喚醒 (while放在這里提現了水准)
                    condition2.await();  //等待
                } catch (InterruptedException e) { e.printStackTrace(); } } for (int j = 1; j <= 100; j++) { System.out.println("sub2 thread sequence of " + j + ", loop of " + i); } shoudeSub = 3; condition3.signal();//喚醒
        } finally{ lock.unlock(); } } public void sub3(int i) { lock.lock(); try { while (shoudeSub != 3) { // 這里也可以用 if ,用while比較好一些 As in the one argument // version, interrupts and spurious wakeups are // possible, and this method should always be // used in a loop
                try { // 防止線程有可能被假喚醒 (while放在這里提現了水准)
                    condition3.await();  //等待
                } catch (InterruptedException e) { e.printStackTrace(); } } for (int j = 1; j <= 20; j++) { System.out.println("sub3 thread sequence of " + j + ", loop of " + i); } shoudeSub = 1; condition1.signal();//喚醒
        } finally{ lock.unlock(); } } public void main(int i) { lock.lock(); try { while (shoudeSub != 1) { try { condition1.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int j = 1; j <= 10; j++) { System.out.println("main thread sequence of " + j + ", loop of "
                        + i); } shoudeSub = 2; condition2.signal(); } finally{ lock.unlock(); } } /** * * synchronized (obj) { 這里的obj與obj.wait必須相同,否則會拋異常 while (<condition does * not hold>) obj.wait(); ... // Perform action appropriate to condition } */ }

 

Condition的一個例子:

 編寫一個程序,開啟3個線程 ,這三個線程的ID分別為 A,B, C,每個線程將自己的ID 在屏幕上打印10遍,要求輸出的結果必須按順序顯示。

如:ABCABCABC.....依次遞歸

這里實現了一個比題目稍微難得例子,A 打印10次,B打印20次 ,C打印5次依次遞歸20次。

package com.java.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestAlternative {

    public static void main(String[] args) {
        final Alternative alternative = new Alternative();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i = 1;i<=20;i++){
                    alternative.loopA(i);
                }
            }
        },"A").start();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i = 1;i<=20;i++){
                    alternative.loopB(i);
                }
            }
        },"B").start();
        new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i = 1;i<=20;i++){
                    alternative.loopC(i);
                    System.out.println("-----------------");
                }
            }
        },"C").start();
        
    }

}

class Alternative{
    
    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    
    void loopA(int outerLoop){
        lock.lock();
        try{
            while(number != 1){
                condition1.await();
            }
            for(int i = 1;i<=10;i++){
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + outerLoop);
            }
            number = 2;
            condition2.signal();
        }catch(Exception e){
        }finally {
            lock.unlock();
        }
    }
    
    void loopB(int outerLoop){
        lock.lock();
        try{
            while(number != 2){
                condition2.await();
            }
            for(int i = 1;i<=20;i++){
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + outerLoop);
            }
            number = 3;
            condition3.signal();
        }catch(Exception e){
            
        }finally{
            lock.unlock();
        }
    }
    void loopC(int outerLoop){
        lock.lock();
        try{
            while(number != 3){
                condition3.await();
            }
            for(int i = 1;i<=5;i++){
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + outerLoop);
            }
            number = 1;
            condition1.signal();
        }catch(Exception e){
            
        }finally{
            lock.unlock();
        }
    }
}

 

 

java5的Semaphere同步工具

  Semaphore實現信號燈

  Semaphore可以維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore可以控制同時訪問資源的線程個數,例如,實現一個文件允許的並發訪問數。

  假設一個文件同時可以被3個人訪問,來了5個人,同時只有3個訪問。3個中任何一個出來后,等待的就可以進去了。

public class SemaphoreTest {

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final  Semaphore sp = new Semaphore(3);  //還有一個構造方法,Semaphore(int permits, boolean fair)  fair參數為true表示誰先來誰先進,一種公平的原則 
        for(int i=0;i<10;i++){
            Runnable runnable = new Runnable(){
                    public void run(){
                    try {
                        sp.acquire();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("線程" + Thread.currentThread().getName() + 
                            "進入,當前已有" + (3-sp.availablePermits()) + "個並發");
                    try {
                        Thread.sleep((long)(Math.random()*10000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("線程" + Thread.currentThread().getName() + 
                            "即將離開");                    
                    sp.release();
                    //下面代碼有時候執行不准確,因為其沒有和上面的代碼合成原子單元
                    System.out.println("線程" + Thread.currentThread().getName() + 
                            "已離開,當前已有" + (3-sp.availablePermits()) + "個並發");                    
                }
            };
            service.execute(runnable);            
        }
    }
}

 

 

單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了 "鎖",再由另外一個線程釋放"鎖",這可應用於死鎖恢復的一些場合。

 

java5 的CyclicBarrier同步工具

/**
 * 表示大家彼此等待,大家集合好后才開始出發,分散活動后又在指定地點集合碰面,
 * 這就好比整個公司的人員利用周末時間集體郊游一樣,先各自從家出發到公司集合后,
 * 再同時出發到公園游玩,在指定地點集合后再同時開始就餐,…。
 * @author Administrator
 *
 */
public class CyclicBarrierTest {

    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newCachedThreadPool();
        final CyclicBarrier cb = new CyclicBarrier(3);
        for (int i = 0; i < 3; i++) {
            Runnable runnable = new Runnable() {
                public void run() {
                    try {
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("線程"+ Thread.currentThread().getName()
                                        + "即將到達集合點1,當前已有 "+(cb.getNumberWaiting()+1) +"個已經到達,"+(cb.getNumberWaiting() == 2?"都到齊了,繼續走啊":"正在等待"));
                        cb.await();
                        
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("線程"+ Thread.currentThread().getName()
                                + "即將到達集合點2,當前已有 "+(cb.getNumberWaiting()+1) +"個已經到達,"+(cb.getNumberWaiting() == 2?"都到齊了,繼續走啊":"正在等待"));
                        cb.await();
                        
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("線程"+ Thread.currentThread().getName()
                                + "即將到達集合點3,當前已有 "+(cb.getNumberWaiting()+1) +"個已經到達,"+(cb.getNumberWaiting() == 2?"都到齊了,繼續走啊":"正在等待"));
                        cb.await();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            };
            threadPool.execute(runnable);
        }
        threadPool.shutdown();
    }

}

 

 

 

java5的CountDownLatch同步工具

  CountDownLatch : 閉鎖,在完成某些運算時,只有其他所有線程的運算全部完成,當前運算才繼續執行

  CountDownLatch應用1:比如要統計5個線程並發的運行時間,即線程的開始時間與最后一個線程的運行結束時間的間隔時間。

  

package com.java.juc;

import java.util.concurrent.CountDownLatch;

public class TestCountDownLatch2 {

    public static void main(String[] args) {

        CountDownLatch latch = new CountDownLatch(5);
        LatchDemo2 ld = new LatchDemo2(latch);
        
        long start = System.currentTimeMillis();
        for(int i = 0;i<5;i++){
            new Thread(ld).start();
        }
        try {
            latch.await();   //先執行完成的線程需要等待還沒有執行完的線程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        long end  = System.currentTimeMillis();
        System.out.println("cost: "+ (end - start));
    }

}

class LatchDemo2 implements Runnable{
    private CountDownLatch latch;
    
    public LatchDemo2(CountDownLatch latch) {
        this.latch = latch;
    }
    
    @Override
    public void run() {

        try {
            synchronized(this){
                for(int i = 0;i<50000;i++){  //找出50000以內的所有偶數
                    if(i % 2 == 0){
                        System.out.println(i);
                    }
                }
            }
        } finally{
            latch.countDown();   //為了讓這一句一定執行可以放在finally中
        }
    }
}

 

 

 

  還可以應用於計算所有種類商品的平均銷售總和,平均銷售時間等,如果使用單線程計算效率非常低,相當於是串行計算。可以使用並行計算,按照商品種類進行區分並行的計算。可以將最終的每個線程的計算結果在進行匯總,可以得出最終的的總的銷售數據,這就可以使用CountDownLatch進行操作,可以大幅度提高效率。(京東)

 

應用:運動員跑步比賽,得到最終的排名需要在所有運動員都完成之后,公布最終的結果。

/**
 * 猶如倒計時計數器,調用CountDownLatch對象的countDown方法就將計數器減一,
 * 當計數器到達0時,則所有等待者或單個等待者開始執行。
 * 可以實現一個人(也可以是多個人)等待其他所有人都來通知他,可以實現一個人通知多個人的效果,
 * 類似裁判一聲口令,運動員同時開始奔跑,或者所有運動員都跑到
 * 終點后裁判才可以公布結果。還可以實現一個計划需要多個領導都簽字后
 * 才能繼續向下實施的情況
 * @author Administrator
 *
 */
public class CountDownLetchTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final CountDownLatch cdOrder = new CountDownLatch(1); //計數器初始值 1
        final CountDownLatch cdAnswer = new CountDownLatch(3);
        for(int i = 0;i<3;i++){
            Runnable runnable = new Runnable() {
                
                @Override
                public void run() {
                    try {
                        System.out.println("線程"+Thread.currentThread().getName()
                                +"正准備接受命令");
                        cdOrder.await();
                        System.out.println("線程"+Thread.currentThread().getName()
                                +"已接受命令");
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("線程"+Thread.currentThread().getName()
                                +"回應命令處理結果");
                        cdAnswer.countDown();
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                }
            };
            executorService.execute(runnable);
        }
        try {
            Thread.sleep((long)(Math.random()*10000));
            System.out.println("線程"+Thread.currentThread().getName()
                    +"即將發布命令");
            cdOrder.countDown();  //計數器數值減 1
            System.out.println("線程"+Thread.currentThread().getName()
                    +"已發送命令,正在等待結果");
            cdAnswer.await();
            System.out.println("線程"+Thread.currentThread().getName()
                    +"已收到所有響應結果");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        executorService.shutdown();
    }
}

 java 中CycliBarriar 和 CountDownLatch 有什么區別?

  這兩個的區別是CyclicBarrier 可以重復使用已經通過的障礙,而 CountdownLatch 不能重復使用。

 

 

java5的Exchanger同步工具

/**
 * 用於實現兩個人之間的數據交換,每個人在完成一定的事物后想與對方交換數據,第一個先拿出數據的人將
 * 一直等待第二個人拿着數據到來時,才能彼此交換數據。
 * @author Administrator
 *
 */
public class ExchangerTest {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Exchanger exchanger = new Exchanger();
        executorService.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    String data1 = "aaa";
                    System.out.println("線程" + Thread.currentThread().getName()
                            + "正在把數據" + data1 + "換出去");
                    Thread.sleep((long) (Math.random() * 10000));
                    String data2 = (String) exchanger.exchange(data1);
                    System.out.println("線程" + Thread.currentThread().getName()
                            + "換回的數據為 " + data2);
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        });
        executorService.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    String data1 = "bbb";
                    System.out.println("線程" + Thread.currentThread().getName()
                            + "正在把數據" + data1 + "換出去");
                    Thread.sleep((long) (Math.random() * 10000));
                    String data2 = (String) exchanger.exchange(data1);
                    System.out.println("線程" + Thread.currentThread().getName()
                            + "換回的數據為 " + data2);
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        });
    }

}

 

打印結果為:

線程 pool-1-thread-1正把數據 aaa 換出去

線程 pool-1-thread-2正把數據 bbb 換出去

線程 pool-1-thread-2換回的數據為 aaa

線程 pool-1-thread-1換回的數據為 bbb

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM