Java:線程併發工具類

1、CountDownLatch 
1.應用場景
 
在實際多線程併發開發過程當中,咱們會遇見不少等待子線程完畢後在繼續執行的狀況,(如多個子線程下載文件,全部子線程執行完畢後再重命名爲文件名)。 
2.使用方式 
CountDownLatch的構造函數接受一個int類型的參數做爲計數器,調用countDwon()方法,計數器減1,await()方法阻塞當前線程,直到計數器變爲0;、 
補充: 
    計數器爲0的時候,調用awaite()方法不會阻塞主線程; 
    初始化後,不能修改計數器的值; 
    可使用await(long time,TimeUnit unit)等待特定時間後,就不阻塞主線程; java

3.實例代碼數據庫

public class Main {   
    //等待2個子線程執行完畢,計數器爲2   
    static CountDownLatch countDownLatch = new CountDownLatch(2);   
   
    public static void main(String[] args) {   
        System.out.println("start subThread doing...");   
        //建立並開啓2個子線程   
        SubThread subThread1 = new SubThread();   
        SubThread subThread2 = new SubThread();   
        subThread1.start();   
        subThread2.start();   
   
        try {   
            //阻塞主線程,等待子線程結束   
            countDownLatch.await();   
        } catch (InterruptedException e) {   
            e.printStackTrace();   
        }   
   
        System.out.println("subThread are finish...");   
    }   
   
    static class SubThread extends Thread {   
        @Override   
        public void run() {   
            //模擬執行任務   
            try {   
                sleep(3000);   
            } catch (InterruptedException e) {   
                e.printStackTrace();   
            }   
            //子線程執行完畢,減小計數器   
            System.out.println(getName() + " done...");   
            countDownLatch.countDown();   
        }   
    }   
}

運行結果:當Thread-一、Thread-0兩個子線程執行完畢後,在運行main線程後續的邏輯 多線程

start subThread doing... 
    Thread-1 done... 
    Thread-0 done... 
    subThread are finish...

2、CyclicBarrier 
1.應用場景 

若是當你碰見須要讓一組線程達到同一個屏障(同步點)時被阻塞,直到最後一個線程達到屏障時,屏障纔會打開的狀況。 
2.使用方式 
CycliBarrier默認的構造方法CyclicBarrier(int parties),參數標識屏障攔截的線程個數,每一個線程調用await()方法告訴SyclicBarrier咱們已經達到屏障了,而後當前線程被阻塞。當全部子線程都達到屏障後,則繼續執行子線程的後續邏輯。 
補充: 
CyclicBarrier還提供了一個更高級的函數CyclicBarrier(int parties,Runnable barrierAction),用於在線程達到屏障時,優先執行barrierAction。 
3.實例代碼 併發

public class Main { 
    //攔截2個子線程屏障 
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2); 
 
    public static void main(String[] args) { 
        System.out.println("start subThread doing..."); 
        SubThread subThread1 = new SubThread(); 
        SubThread subThread2 = new SubThread(); 
        subThread1.start(); 
        subThread2.start(); 
    } 
 
    static class SubThread extends Thread { 
        @Override 
        public void run() { 
            try { 
                System.out.println(getName() + " doing first things."); 
                //模擬子線程執行第一個任務 
                sleep(3000); 
                System.out.println(getName() + " done first things."); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
             
            try { 
                //完成第一個任務,告知達到屏障 
                cyclicBarrier.await(); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } catch (BrokenBarrierException e) { 
                e.printStackTrace(); 
            } 
 
 
            //全部子線程都完成第一個任務後,繼續運行每一個子線程的下一個任務 
            System.out.println(getName() + " doing other things."); 
        } 
    } 
}

運行結果:當子線程都執行完第一個任務到達屏障後,執行下一個任務 ide

start subThread doing... 
Thread-0 doing first things. 
Thread-1 doing first things. 
Thread-1 done first things. 
Thread-0 done first things. 
Thread-0 doing other things. 
Thread-1 doing other things.

3、Semaphore 
1.應用場景
 
多線程訪問公共資源的狀況在開發過程當中常常碰見,如數據庫鏈接,可能開啓幾十個線程進行併發讀取,可是考慮到數據庫鏈接性能和消耗,咱們必須控制10個線程哪一個是鏈接數據庫。Semaphore就是用來控制同時訪問特定資源的線程數量。 
2.使用方式 
Semaphore的構造方法Semaphore(int permits),permits標識許可證數量。執行任務前,acquire()方法獲取一個許可證;任務執行完成後調用relese()方法歸還許可證。沒有得到許可證的子線程就阻塞等待。 
補充: 
tryAcquire():嘗試獲取許可證; 
intavaliablePermits():返回信號量中當前許可證的個數; 
intgetQueueLength():返回正在等待獲取許可證的線程個數; 
booleanhasQueueThreads():是否有線程正在等待許可證; 
reducePermits(int reduction):減小reduction個許可證; 
getQueuedThreads():返回全部等待獲取許可證的線程集合; 
3.實例代碼 函數

public class Main { 
    //建立2個許可證 
    static Semaphore semaphore = new Semaphore(2); 
 
    public static void main(String[] args) { 
        System.out.println("start subThread doing..."); 
        //同時開啓4個子線程運行 
        for (int i = 0; i < 4; i++) { 
            SubThread subThread = new SubThread(); 
            subThread.start(); 
        } 
    } 
 
    static class SubThread extends Thread { 
        @Override 
        public void run() { 
            try { 
                //執行任務前獲取許可證 
                semaphore.acquire(); 
                System.out.println(getName() + "doing things."); 
                sleep(3000); 
                //執行完任務釋放許可證 
                semaphore.release(); 
                System.out.println(getName() + "finish things."); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
}

運行結果:同時只有2個線程運行,當某個線程運行完畢釋放許可後,下一個線程才獲取許可運行; 性能

start subThread doing... 
Thread-0doing things. 
Thread-1doing things. 
Thread-1finish things. 
Thread-2doing things. 
Thread-0finish things. 
Thread-3doing things. 
Thread-2finish things. 
Thread-3finish things.

4、Exchanger 
1.應用場景 

在某些實際業務如流水錄入中,爲了不錯誤。採用兩我的同時錄入,並對比錄入的結果是否一致。Exchanger用於進行線程之間的數據交換,它提供了一個同步點,兩個線程能夠交換彼此的數據。 
2.使用方式 
兩個線程經過exchange()方法交換數據,若是一個線程執行exchange()方法,它會一直等待第二個線程也執行exchange()方法。當兩個線程都達到同步點時,就能夠交換數據,將本線程產生的數據傳遞給對方。 
3.實例代碼 ui

public class Main { 
    //用戶線程間交換數據(String)對象exchanger 
    static Exchanger<String> exchanger = new Exchanger<>(); 
 
    public static void main(String[] args) { 
        //建立2個子線程分別執行 
        SubThread1 subThread1 = new SubThread1(); 
        SubThread2 subThread2 = new SubThread2(); 
        subThread1.start(); 
        subThread2.start();  
    } 
 
    static class SubThread1 extends Thread { 
        @Override 
        public void run() { 
            try { 
                System.out.println(getName() + "start doing..."); 
                //模擬執行完成後,獲取結果result1,並將result1交換給對方線程 
                sleep(3000); 
                String result1 = "3000"; 
                String result2 = exchanger.exchange(result1); 
                //待兩個線程都執行完畢後,交換數據進行比較 
                System.out.println(getName() + " thread1 result:" + result1 + " is equals thread2 result:" + result2 + 
                        "," + result1.equals(result2)); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
 
    static class SubThread2 extends Thread { 
        @Override 
        public void run() { 
            try { 
                System.out.println(getName() + "start doing..."); 
                //模擬執行完成後,獲取結果result2,並將result2交換給對方線程 
                sleep(2000); 
                String result2 = "2000"; 
                String result1 = exchanger.exchange(result2); 
                //待兩個線程都執行完畢後,交換數據進行比較 
                System.out.println(getName() + " thread1 result:" + result1 + " is equals thread2 result:" + result2 + 
                        "," + result1.equals(result2)); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
}

運行結果:線程1優先執行完畢,等待線程0執行完畢後,交換數據分別進行結果比較 線程

Thread-1start doing... 
Thread-0start doing... 
Thread-1finish doing... 
Thread-0finish doing... 
Thread-0 thread1 result:3000 is equals thread2 result:2000,false 
Thread-1 thread1 result:3000 is equals thread2 result:2000,false
相關文章
相關標籤/搜索