java初入多線程9

ReadWriteLock 多寫(xiě)鎖

  1. ReadWriteLock 是JDK5中提供的讀寫(xiě)分離鎖,讀寫(xiě)分離可以有效的幫助減少鎖競(jìng)爭(zhēng)。用來(lái)提高系統(tǒng)性能。
    讀寫(xiě)鎖的訪問(wèn)約束情況
寫(xiě)
非阻塞 阻塞
寫(xiě) 堵塞 阻塞
  • 讀讀 之間不互斥:讀讀之間不阻塞
  • 讀-寫(xiě)互斥:讀阻塞寫(xiě),寫(xiě)也會(huì)阻塞讀
  • 寫(xiě)- 寫(xiě) 互斥: 寫(xiě)寫(xiě)堵塞。
public class ReadWriteLockDemo {
    private static Lock lock = new ReentrantLock();
    private static ReentrantReadWriteLock readWriteLock = new  ReentrantReadWriteLock();
    
    private static Lock readLock = readWriteLock.readLock();
    private static Lock writeLock =readWriteLock.writeLock();
    
    private int value ;
    
    
    public Object handleRead(Lock lock) throws InterruptedException {
        try {
            lock.lock();
            Thread.sleep(1000);
            return value;
            
        }finally {
            lock.unlock();
        }
    }
    
    public void handleWrite(Lock lock,int index) throws InterruptedException{
        try {
            lock.lock();  //模擬寫(xiě)的操作
            Thread.sleep(1000);
            value=index;
        } finally {
            lock.unlock();
        }
    }
    
    public static void main(String[] args) {
        final ReadWriteLockDemo  demo= new ReadWriteLockDemo();
        Runnable readRunnable =new Runnable() {
            
            public void run() {
                try {
//                  demo.handleRead(readLock);
                    demo.handleRead(lock);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
        };
        
        Runnable writerRunnable =new Runnable() {
            
            public void run() {
                try {
//                  demo.handleWrite(writeLock, new Random().nextInt());
                    demo.handleWrite(lock, new Random().nextInt());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
            }
        };
        
        for (int i = 18; i < 20; i++) {
            new Thread(writerRunnable).start();
        }
    }
    
}

  • 在代碼中我們使用了兩種方式 如果使用讀寫(xiě)鎖的該程序執(zhí)行可以在2秒內(nèi)執(zhí)行完畢,但是如果是lock鎖的沒(méi)有進(jìn)行多寫(xiě)分離,那么會(huì)在將近20秒的時(shí)間內(nèi)完成。為什么會(huì)這么長(zhǎng)時(shí)間 ,是因?yàn)樗械淖x線程與寫(xiě)線程之間 必須都互相等待 ,導(dǎo)致的。讀寫(xiě)分離之后 讀讀之間不用互相等待 ,大大減少時(shí)間。

倒計(jì)時(shí)器:CountDownLatch

  • CountDownLatch 是一個(gè)非常實(shí)用的多線程控制工具類(lèi)。主要是用來(lái)控制線程等待,它可以讓某一個(gè)線程等待到知道倒計(jì)時(shí)結(jié)束再開(kāi)始執(zhí)行。代碼演示如下:
public class CountDownLatchDemo implements Runnable {

    static final CountDownLatch end = new  CountDownLatch(10);
    static final CountDownLatchDemo  demo = new CountDownLatchDemo();
    
    
    @Override
    public void run() {
        
        try {
            
            //模擬檢查任務(wù) 
            Thread.sleep(new Random().nextInt(10)*1000);
            System.out.println("check complete");
            end.countDown();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }

    public static void main(String[] args) throws Exception {
        ExecutorService exec = new  ThreadPoolExecutor(10, 10,
                  0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
        for(int i = 0 ; i < 10 ; i++){
            exec.submit(demo);
        }
        
        //等待檢查
        end.await();
        
        // 發(fā)射  相當(dāng)于開(kāi)始執(zhí)行任務(wù)
        System.out.println("fire");
        
        exec.shutdown();
    }
}

結(jié)果圖
  • 在上述代碼中 計(jì)數(shù)器數(shù)量為10 ,那么就是需要有10個(gè)線程完成任務(wù),在CountDownLatch 上的線程才能繼續(xù)執(zhí)行。 在代碼中我們能看到有個(gè)countdown()方法, 就是用來(lái)通知CountDownLatch, 如果一個(gè)線程完成任務(wù),那么倒計(jì)時(shí)器就可以減1.。 我們?cè)赼wait 方法,要求主線程等待所有10個(gè)檢查任務(wù)全部完成,那么主線程才會(huì)繼續(xù)執(zhí)行。
示意圖

循環(huán)柵欄 :CyclicBarrier

  • 這是一種不同于 CountDOwnLatch 的多線程并發(fā)控制工具,但是也可以實(shí)現(xiàn)線程間的計(jì)數(shù)等待。它比CountDownLatch 功能更加強(qiáng)大且復(fù)雜。
  • 循環(huán)柵欄 意思就是循環(huán),如果我們使用的是其計(jì)數(shù)器的功能那么如果是20個(gè),等到計(jì)數(shù)器歸0 之后還會(huì)湊齊下一批20個(gè)線程,再次形成柵欄。代碼如下:
public class CyclicBarrierDemo {
        
    
    public static class Soldier implements Runnable{
        private String soldier;
        private final  CyclicBarrier cyclic ;
        
        public Soldier( CyclicBarrier cyclic , String soldier) {
            this.cyclic = cyclic ;
            this.soldier = soldier ;
        }
        
        @Override
        public void run() {
            try {
                //等到所有任務(wù)的到來(lái)
                cyclic.await() ;
                doWork();
                
                //等待所有任務(wù)完成
                cyclic.await();
                
            } catch (Exception e) {
                // TODO: handle exception
            }
            
        
        }
        
        void doWork(){
            try {
                Thread.sleep(Math.abs(new Random().nextInt()%10_000));
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }
    
    public static class BarrierRun implements Runnable {
        boolean flag ;
        int  N ;
        public BarrierRun(boolean flag, int n) {
            this.flag = flag;
            N = n;
        } 
        
        @Override
        public void run() {
            if(flag){
                System.out.println("司令 : 士兵"+ N + "個(gè),任務(wù)完成");
            }else{
                System.out.println("司令 : 士兵"+ N + "個(gè),集合完畢");
            }
            
        }
        
        
    }
    public static void main(String[] args) {
        final int N = 10 ;
        Thread[] allSoldier = new Thread[N];
        boolean flag = false ; 
        CyclicBarrier cyclic =new CyclicBarrier(N, new BarrierRun(flag, N));
        
        //設(shè)置屏障點(diǎn),主要是為了執(zhí)行這個(gè)方法
        System.out.println("集合隊(duì)伍!");
        
        for(int i = 0 ; i < N ; i++ ){
            System.out.println("士兵 "+ i + " 報(bào)道 ");
            allSoldier[i] = new  Thread(new Soldier(cyclic, " 士兵 " + i));
            allSoldier[i].start();
        }
        
    }
}
  • 根據(jù)代碼中,我們可以發(fā)現(xiàn) 執(zhí)行await 方法的時(shí)候 可能會(huì)拋出異常, 一個(gè)是等待異常InterruptedException,這個(gè)是方便相應(yīng) 外部緊急事件,另外一個(gè)異常是BrokenBarrierException ,這個(gè)表示 CyclicBarrier 已經(jīng)損壞, 系統(tǒng)沒(méi)法等到所有線程然后再開(kāi)始執(zhí)行,處理是把所有線程中斷 。就避免 線程的永久的等待了


    執(zhí)行結(jié)果
  • 整個(gè)過(guò)程的流程圖如下:


    示意圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來(lái)是分開(kāi)三篇的,后來(lái)想想還是整...
    coder_pig閱讀 1,772評(píng)論 2 17
  • 1.解決信號(hào)量丟失和假喚醒 public class MyWaitNotify3{ MonitorObject m...
    Q羅閱讀 1,005評(píng)論 0 1
  • 時(shí)光已無(wú)可逆轉(zhuǎn)的置換那個(gè)楓葉紅遍的地方校園小徑上還有幾株玉蘭花悄悄綻放這是江南最靜謐的季節(jié)偶爾從小巷子傳來(lái)小販的叫...
    郭安安閱讀 337評(píng)論 4 7
  • 1.ScreenToViewportPoint,WorldToViewportPoint,ViewportToWo...
    胤醚貔貅閱讀 953評(píng)論 0 1
  • 桌子上的日記被木子翻得一團(tuán)亂,"嘖嘖,姐姐你真的就那么喜歡他,喜歡他什么?"木子扔掉手里的日記歪著腦袋問(wèn)林安。...
    湯小媛閱讀 631評(píng)論 2 4

友情鏈接更多精彩內(nèi)容