1. 程式人生 > >Java基礎知識-java.util.concurrent包下常見類的使用

Java基礎知識-java.util.concurrent包下常見類的使用

finall iss con value 通信 out 否則 app ted

一,Condition

一個場景,兩個線程數數,同時啟動兩個線程,線程A數1、2、3,然後線程B數4、5、6,最後線程A數7、8、9,程序結束,這涉及到線程之間的通信。

public class ConditionTest {
    static class NumberWrapper {
        public int value = 1;
    }

    public static void main(String[] args) {
        //初始化可重入鎖
        final Lock lock = new ReentrantLock();
        
        
//第一個條件當屏幕上輸出到3 final Condition reachThreeCondition = lock.newCondition(); //第二個條件當屏幕上輸出到6 final Condition reachSixCondition = lock.newCondition(); //NumberWrapper只是為了封裝一個數字,一邊可以將數字對象共享,並可以設置為final //註意這裏不要用Integer, Integer 是不可變對象 final NumberWrapper num = new
NumberWrapper(); //初始化A線程 Thread threadA = new Thread(new Runnable() { @Override public void run() { //需要先獲得鎖 lock.lock(); System.out.println("ThreadA獲得lock"); try { System.out.println(
"threadA start write"); //A線程先輸出前3個數 while (num.value <= 3) { System.out.println(num.value); num.value++; } //輸出到3時要signal,告訴B線程可以開始了 reachThreeCondition.signal(); } finally { lock.unlock(); System.out.println("ThreadA釋放lock"); } lock.lock(); try { //等待輸出6的條件 System.out.println("ThreadA獲得lock"); reachSixCondition.await(); System.out.println("threadA start write"); //輸出剩余數字 while (num.value <= 9) { System.out.println(num.value); num.value++; } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println("ThreadA釋放lock"); } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { lock.lock(); System.out.println("ThreadB獲得lock"); Thread.sleep(5000);//是await方法釋放了鎖 while (num.value <= 3) { //等待3輸出完畢的信號 reachThreeCondition.await(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println("ThreadB釋放lock"); } try { lock.lock(); System.out.println("ThreadB獲得lock"); //已經收到信號,開始輸出4,5,6 System.out.println("threadB start write"); while (num.value <= 6) { System.out.println(num.value); num.value++; } //4,5,6輸出完畢,告訴A線程6輸出完了 reachSixCondition.signal(); } finally { lock.unlock(); System.out.println("ThreadB釋放lock"); } } }); //啟動兩個線程 threadB.start(); threadA.start(); } }

創建方式:通過Lock創建,Lock.newCondition();

常用方法:

await():阻塞,直到相同的Condition調用了signal方法。
signal():通知。

總結:Condition必須與Lock一起使用(wait()、notify()必須與synchronized一起使用,否則運行會報錯java.lang.IllegalMonitorStateException),相比於wait與notify更加的靈活,可以設置各種情形,如上例中的到達3和到達6兩個條件。

二,CountDownLatch

直接上代碼:

public class CountDownLatchTest {
    public static void main(String[] args) {
        final CountDownLatch c = new CountDownLatch(3);//總數3
        Thread t1 = new Thread(new Runnable(){
            @Override
            public void run() {
                try {
                    System.out.println("開始等");
                    c.await();//阻塞,等待countDown,當countDown到0就執行後面的完事了
                    System.out.println("完事");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
        });
        Thread t2 = new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i=3;i>0;i--){
                    c.countDown();//減1
                }
            }
            
        });
        t1.start();
        t2.start();
    }
}

創建方式:直接創建,new CountDownLatch(int num);

常用方法:

await():阻塞,直到countDown方法被執行了num次。
countDown():減

總結:適用於一個線程等待其他線程的情景。

三,CyclicBarrier

通過代碼思考一下與CountDownLatch的區別。

public class MainMission {
    private CyclicBarrier barrier;
    private final static int threadCounts = 5;
    public void runMission() {
        ExecutorService exec=Executors.newFixedThreadPool(threadCounts);
        //new 的時候要傳入數字,我發現,這個類似semaphore,如果位置不足,線程會搶位置。數字要是threadCounts+1為主線程留一個位子,但實際測試中發現,只要等於threadCount就可以
         barrier=new CyclicBarrier(threadCounts+1); 
        for(int i=0;i<5;i++){
            exec.execute(new Mission(barrier));
        }
        try {
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有任務都執行完了");
        exec.shutdown();//如果不關閉,程序一直處於運行狀態
    }
    public static void main(String[] args) {
        MainMission m = new MainMission();
        m.runMission();
    }
}
class Mission implements Runnable{
    private CyclicBarrier barrier;
    public Mission(CyclicBarrier barrier){
        this.barrier = barrier;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"開始執行任務");
        try {
            int sleepSecond = new Random().nextInt(10)*1000;
            System.out.println(Thread.currentThread().getName()+"要執行"+sleepSecond+"秒任務");
            Thread.sleep(sleepSecond);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"執行完畢");
    }
}

創建方式:直接創建,new CyclicBarrier(int num);

常用方法:

await():阻塞,直到阻塞的線程數量達到num個。

總結:想想一下百米跑,所有運動員都就位之後才會發令起跑,線程調用await意味著說,我準備好了。

Java基礎知識-java.util.concurrent包下常見類的使用