Java同步工具類總結

先談談閉鎖和柵欄的區別:

1.關鍵區別在於,全部線程必須同時到達柵欄位置,才能繼續執行。html

2.閉鎖用於等待某一個事件的發生,舉例:CountDownLatch中await方法等待計數器爲零時,全部事件纔可繼續執行。而柵欄是等待其餘線程到位,全部事件纔可繼續下一步。例如:幾個家庭決定在某個地方集合:「全部人6:00在麥當勞碰頭,到了之後要等其餘人,以後再討論下一步要作的事情」。java

Semaphore(閉鎖)

這個東西和以前的synchronized乾的事差很少。
synchronized保證了,我管理的那部分代碼同一時刻只有一個線程能訪問
Semaphore保證了,我管理的那部分代碼同一時刻最多能夠有n個線程訪問併發

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Semaphore;  
  
  
public class SemaphoreTest {  
    public static void main(String[] args) {  
        ExecutorService service = Executors.newCachedThreadPool();  
        final  Semaphore sp = new Semaphore(3);  
        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);            
        }  
    }  
  
  
}  

 運行結果以下:dom

線程pool-1-thread-2進入,當前已有2個併發
線程pool-1-thread-1進入,當前已有2個併發
線程pool-1-thread-3進入,當前已有3個併發
線程pool-1-thread-1即將離開
線程pool-1-thread-1已離開,當前已有2個併發
線程pool-1-thread-4進入,當前已有3個併發
線程pool-1-thread-3即將離開
線程pool-1-thread-3已離開,當前已有2個併發
線程pool-1-thread-5進入,當前已有3個併發
線程pool-1-thread-2即將離開
線程pool-1-thread-2已離開,當前已有2個併發
線程pool-1-thread-6進入,當前已有3個併發
線程pool-1-thread-4即將離開
線程pool-1-thread-4已離開,當前已有2個併發
線程pool-1-thread-7進入,當前已有3個併發
線程pool-1-thread-5即將離開
線程pool-1-thread-5已離開,當前已有2個併發
線程pool-1-thread-8進入,當前已有3個併發
線程pool-1-thread-8即將離開
線程pool-1-thread-9進入,當前已有3個併發
線程pool-1-thread-8已離開,當前已有3個併發
線程pool-1-thread-6即將離開
線程pool-1-thread-6已離開,當前已有2個併發
線程pool-1-thread-10進入,當前已有3個併發
線程pool-1-thread-10即將離開
線程pool-1-thread-10已離開,當前已有2個併發
線程pool-1-thread-7即將離開
線程pool-1-thread-7已離開,當前已有1個併發
線程pool-1-thread-9即將離開
線程pool-1-thread-9已離開,當前已有0個併發

 參考連接:http://www.cnblogs.com/nullzx/archive/2016/03/12/5270233.html ui

CountDownLatch (閉鎖)

它保證了什麼功能呢?其實和CycliBarrier也相似。線程

看下面這個圖htm

這就是CycleBarrier,線程本身管理本身,你們看到人都到齊了,才繼續走。


blog

這個是CountDownLatch,由他人來協調進度。事件

例如跑步的時候,有個裁判,等全部的人都到齊了,他吹哨,而後你們開始跑,等全部人都跑完了,他才公佈成績。get

import java.util.concurrent.CountDownLatch;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
  
public class CountdownLatchTest {  
  
  
    public static void main(String[] args) {  
        ExecutorService service = Executors.newCachedThreadPool();  
        final CountDownLatch cdOrder = new CountDownLatch(1);  
        final CountDownLatch cdAnswer = new CountDownLatch(3);        
        for(int i=0;i<3;i++){  
            Runnable runnable = new Runnable(){  
                    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) {  
                        e.printStackTrace();  
                    }                 
                }  
            };  
            service.execute(runnable);  
        }         
        try {  
            Thread.sleep((long)(Math.random()*10000));  
          
            System.out.println("線程" + Thread.currentThread().getName() +   
                    "即將發佈命令");                        
            cdOrder.countDown();  
            System.out.println("線程" + Thread.currentThread().getName() +   
            "已發送命令,正在等待結果");      
            cdAnswer.await();  
            System.out.println("線程" + Thread.currentThread().getName() +   
            "已收到全部響應結果");     
        } catch (Exception e) {  
            e.printStackTrace();  
        }                 
        service.shutdown();  
  
  
    }  
}  

 運行結果以下

線程pool-1-thread-3正準備接受命令
線程pool-1-thread-1正準備接受命令
線程pool-1-thread-2正準備接受命令
線程main即將發佈命令
線程main已發送命令,正在等待結果
線程pool-1-thread-3已接受命令
線程pool-1-thread-2已接受命令
線程pool-1-thread-1已接受命令
線程pool-1-thread-3迴應命令處理結果
線程pool-1-thread-1迴應命令處理結果
線程pool-1-thread-2迴應命令處理結果
線程main已收到全部響應結果

 

CountDownLatch裏面有個計數器,初始值就是new countdownlatch時傳入的

wait方法會一直等待,直到計數器的值變爲0

coutdown方法可讓計數器的值減一

 

CycleBarrier(柵欄)

CycleBarrier 能作到讓n個線程互相等待,當n個線程都作到某一步後,再繼續下一步。

例以下面的例子,5我的去旅遊,設置abc三個中途節點,全部人都到達a以後在繼續走向b,全部人都到達b,而後才繼續走向c。

 

import java.util.concurrent.CyclicBarrier;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
  
public class CyclicBarrierTest {  
  
  
    public static void main(String[] args) {  
        ExecutorService service = 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) {  
                        e.printStackTrace();  
                    }                 
                }  
            };  
            service.execute(runnable);  
        }  
        service.shutdown();  
    }  
}  

運行結果以下:

 

線程pool-1-thread-2即將到達集合地點1,當前已有1個已經到達,正在等候
線程pool-1-thread-1即將到達集合地點1,當前已有2個已經到達,正在等候
線程pool-1-thread-3即將到達集合地點1,當前已有3個已經到達,都到齊了,繼續走啊
線程pool-1-thread-1即將到達集合地點2,當前已有1個已經到達,正在等候
線程pool-1-thread-3即將到達集合地點2,當前已有2個已經到達,正在等候
線程pool-1-thread-2即將到達集合地點2,當前已有3個已經到達,都到齊了,繼續走啊
線程pool-1-thread-1即將到達集合地點3,當前已有1個已經到達,正在等候
線程pool-1-thread-2即將到達集合地點3,當前已有2個已經到達,正在等候
線程pool-1-thread-3即將到達集合地點3,當前已有3個已經到達,都到齊了,繼續走啊

 

Exchange(柵欄)

A線程有數據1,它須要與B線程的數據2作交換
B線程有數據2,它須要與A線程的數據1作交換

那麼何時交換呢?得等AB都作好準備才行。

import java.util.concurrent.Exchanger;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
  
  
public class ExchangerTest {  
  
  
    public static void main(String[] args) {  
        ExecutorService service = Executors.newCachedThreadPool();  
        final Exchanger<String> exchanger = new Exchanger<String>();  
        service.execute(new Runnable(){  
            public void run() {  
                try {                 
  
  
                    String data1 = "zxx";  
                    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){  
                      
                }  
            }     
        });  
        service.execute(new Runnable(){  
            public void run() {  
                try {                 
  
  
                    String data1 = "lhm";  
                    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){  
                      
                }                 
            }     
        });       
    }  
}  

 運行結果以下:

 

線程pool-1-thread-1正在把數據zxx換出去
線程pool-1-thread-2正在把數據lhm換出去
線程pool-1-thread-2換回的數據爲zxx
線程pool-1-thread-1換回的數據爲lhm
相關文章
相關標籤/搜索