多線程(三)

繼上一次講的開始說吧。

new ThreadPoolExecutor() 自定義參數,理解每個參數什麼含義,具體到某些業務場景,還要看具體怎麼用。在此,再解釋下核心線程數跟最大線程數到底有什麼作用。舉個例子:

new ThreadPoolExecutor(1,2,60,TimeUnit.Days,ArrayBlockingQueue),這個ArrayBlockingQueue  = new ArrayBlockingQueue(4),某個業務場景,需要執行7個sql,交給了ThreadExecutor來執行,ThreadExecutor 核心線程數只有1個,所以ThreadExecutor會執行第一個sql,這時候沒執行完,剩下的6個sql 會放到queue中,由於ArrayBlockingQueue是個有界隊列,最多隻會放下4個任務, (LinkedBlockingQueue是無界隊列,所以想放多少任務都可以),剩下兩個任務,ThreadPoolExecutor 會用 max線程數-核心線程數,直接new 對象去執行。上面例子,因爲最多有2個線程,核心線程只有一個,所以還有一個線程,程序發現,我線程不夠用啊,因爲還有兩個子任務,那我就報錯吧。

demo:

public class UseThreadExecutorPool implements Runnable {
    private static AtomicInteger count = new AtomicInteger();

    @Override
    public void run() {
        int all = count.incrementAndGet();
        System.out.println(all);
    }

    //自定義線程池  各個參數什麼意思 corePoolSize 核心線程數,maximumPoolSize 最大線程數,
    //當 任務數量 <= corePoolSize 直接執行,    maximumPoolSize =>任務數量 > corePoolSize ,任務數量-corePoolSize 的任務 加到queue裏面,拿corePoolSize 線程執行,
    // maximumPoolSize < 任務數量  在不超過 maximumPoolSize的情況下 新建線程執行 加滿queue之後的 任務,當超過了最大線程數,就報錯,
    public static void main(String[] args) {
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<UseThreadExecutorPool>(4);
        ExecutorService executorService = new ThreadPoolExecutor(1, 2, 60, TimeUnit.DAYS, arrayBlockingQueue);

        UseThreadExecutorPool useThreadExecutorPool0 = new UseThreadExecutorPool();
        UseThreadExecutorPool useThreadExecutorPool1 = new UseThreadExecutorPool();
        UseThreadExecutorPool useThreadExecutorPool2 = new UseThreadExecutorPool();
        UseThreadExecutorPool useThreadExecutorPool3 = new UseThreadExecutorPool();
        UseThreadExecutorPool useThreadExecutorPool4 = new UseThreadExecutorPool();
        UseThreadExecutorPool useThreadExecutorPool5 = new UseThreadExecutorPool();
        UseThreadExecutorPool useThreadExecutorPool6 = new UseThreadExecutorPool();

        executorService.execute(useThreadExecutorPool0);
        executorService.execute(useThreadExecutorPool1);
        executorService.execute(useThreadExecutorPool2);
        executorService.execute(useThreadExecutorPool3);
        executorService.execute(useThreadExecutorPool4);
        executorService.execute(useThreadExecutorPool5);
        executorService.execute(useThreadExecutorPool6);

        executorService.shutdown();
    }
}
,當然呢,這個錯誤是可以自己處理的,詳細看上一篇博客。

-----------------------------------------------------------------------------

下面談談CyclicBarrier 、CountDownLatch 和 信號量。

先說下CyclicBarrier 和CountDownLatch吧。這倆都可以實現實時通知,類似於分佈式的並行計算,區別就是CyclicBarrier 是喚起多個線程,CountDownLatch喚起一個線程,舉例個業務場景,運動五個跑步選手比賽,發令槍沒響之前,各自幹各自的事,喝水啊,綁鞋帶啊,但是喊準備的時候,就統一聽發令員的槍聲了,下面看下例子

public class UseCyclicbarrier {
    static class Runner implements Runnable {
        private CyclicBarrier barrier;
        private String name;

        public Runner(CyclicBarrier barrier, String name) {
            this.barrier = barrier;
            this.name = name;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(5000);
                System.out.println(name + " 準備好了 ");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(name + "go");
        }
    }

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3);
        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.submit(new Thread(new Runner(barrier, "小明")));
        executor.submit(new Thread(new Runner(barrier, "小白")));
        executor.execute(new Thread(new Runner(barrier, "小紅")));
        executor.shutdown();
    }
}
CyclicBarrier 初始化後面寫個3,意思就是對象得調用三次await()方法,才能一同喚起,做自己的操作,兩個就不行,會一直等待。三個線程都準備好了,才一起開始。這就是CyclicBarrier 。記住,CyclicBarrier 是喚起子線程,下面講的CountDownLatch 是喚起一個線程,類似於統計的操作,舉個CountDownLatch的demo

public class UseCountDownLatch {
    public static void main(String[] args) {
        final CountDownLatch countDownLatch = new CountDownLatch(2);

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("進入t1 等待其他線程執行完畢");
                try {
                    countDownLatch.await();
                    System.out.println("執行完畢");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("進入t2 ");
                try {
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("進入t3 ");
                try {
                    countDownLatch.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}
可以把代碼粘貼到自己的編輯器裏面,自己慢慢體會這兩者的區別

信號量:說到信號量,不得不說的一個詞叫分流,限流,這是在應用架構中經常性聽到的詞,什麼意思呢,就是一個應用系統最大能承受10個客戶,當前有20個客戶,可以從網絡層限制,也可以從服務層限制,還可以從java層面去限制,java層面就是用的信號量,信號量可以定義當前可以處理多少個請求,達到分流的效果。服務層呢可以用nginx做分流,限流。網絡層的話 類似於cdn做鏡像,這也是分流,限流的一種策略。代碼不展示了,百度下一堆,知道什麼意思就行。

下面說說英文單詞;

pv:每個頁面的訪問量,不計算單個ip,刷新一個即計數。

uv:最小請求單位(ip,每天只統計一次)

qps(tps):每秒請求數 

rt:每個request請求的返回時間。

這些名詞,有可能在做自動化測試的時候提到。

----------------------------------------------------------------------------------------

下面說說  重入鎖 跟 讀寫鎖:也就是Lock 跟RetreentLock,這兩者與sync 有什麼區別呢,1.8以前sync性能不太好,1.8以後沒區別,如果非要問1.8以後的區別的話,Lock鎖更加簡單化,隨性化。RetreentLock 試用場景 讀多寫少 ,讀少寫多的話可以使用RetreentReadWriteLock  代碼不展示,

還有兩個鎖是 readLock 跟 writeLock。記住一個方言就是,讀讀共享,讀寫互斥,寫寫互斥。

下篇博客談談disruptor併發框架。(一個很nb的併發框架)

      


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章