JUC的世界III

失敗者,每每是熱度只有五分鐘的人;成功者,每每是堅持最後五分鐘的人。
你好,我是夢陽辰,期待與你相遇!java

01.線程池

10年前單核CPU電腦,假的多線程,像馬戲團小丑玩多個球,CPU須要來回切換。如今是多核電腦,多個線程各自跑在獨立的CPU上,不用切換效率高。api

線程池的優點:
線程池作的工做只要是控制運行的線程數量,處理過程當中將任務放入隊列,而後在線程建立後啓動這些任務,若是線程數量超過了最大數量,超出數量的線程排隊等候,等其餘線程執行完畢,再從隊列中取出任務來執行。數組

它的主要特色爲:線程複用;控制最大併發數;管理線程多線程

第一:下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的銷耗。併發

第二:提升響應速度。當任務到達時,任務能夠不須要等待線程建立就能當即執行。框架

第三:提升線程的可管理性。線程是稀缺資源,若是無限制的建立,不只會銷耗系統資源,還會下降系統的穩定性,使用線程池能夠進行統一的分配,調優和監控。dom

02.線程池的使用

java.util.concurrent Interface Executor

子接口:異步

java.util.concurrent Interface ExecutorService

在這裏插入圖片描述
Executors是一個輔助工具類。ide

Executors.newFixedThreadPool(int)執行長期任務性能好,建立一個線程池,—池
有N個固定的線程,有固定線程數的線程
package Part5;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);//一個池5個受理線程,相似於一個銀行有五個受理窗口
        try{
            //模擬20個顧客辦理業務
            for(int i = 1;i<=20;i++){
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"\t 在辦理業務!");
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }
    }}

在這裏插入圖片描述

2.Executors.newSingleThreadExecutor()一個任務一個任務的執行,一池一線程

3.Executors.newCachedThreadPool()執行不少短時間異步任務,線程池根據須要建立新線程,
但在先前構建的線程可用時將重用它們。可擴容,遇強則強
package Part5;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        //ExecutorService threadPool = Executors.newFixedThreadPool(5);//一個池5個受理線程,相似於一個銀行有五個受理窗口
        //ExecutorService threadPool = Executors.newSingleThreadExecutor();//一個池1個受理線程,相似於一個銀行有1個受理窗口
        ExecutorService threadPool = Executors.newCachedThreadPool();//一個池N個受理線程,相似於一個銀行有N個受理窗口

        try{
            //模擬20個顧客辦理業務
            for(int i = 1;i<=20;i++){
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"\t 在辦理業務!");
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }
    }}

在這裏插入圖片描述

03.線程池幾個重要的參數

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

在這裏插入圖片描述

04.線程池底層工做原理

在這裏插入圖片描述
一、在建立了線程池後,開始等待請求。函數

二、當調用execute()方法添加一個請求任務時,線程池會作出以下判斷:
2.1若是正在運行的線程數量小於corePoolSize,那麼立刻建立線程運行這個任務;2.2若是正在運行的線程數量大於或等於corePoolSize,那麼將這個任務放入隊列;

2.3若是這個時候隊列滿了且正在運行的線程數量還小於maximumPoolSize,那麼仍是要建立非核心線程立2.4若是隊列滿了且正在運行的線程數量大於或等於maximumPoolSize,那麼線程池會啓動飽和拒絕策略來

三、當一個線程完成任務時,它會從隊列中取下一個任務來執行。

四、當一個線程無事可作超過必定的時間(keepAliveTime)時,線程會判斷:

若是當前運行的線程數大於corePoolSize,那麼這個線程就被停掉。
因此線程池的全部任務完成後,它最終會收縮到corePoolSize的大小。

強制線程池不容許使用Executors 去建立,而是經過ThreadPoolExecutor的方式這樣的處理方式讓寫的同窗更加明確線程池的運行規則,規避資源耗盡的風險。
說明: Executors返回的線程池對象的弊端以下:

  1. FixedThreadPool和 singleThreadPool:
    容許的請求隊列長度爲Integer.MAx_VALUE,可能會堆積大量的請求,從而致使OOM

  2. cachedThreadPool和 ScheduledThreadPool:
    容許的建立線程數量爲Integer.NAX_VALUE,可能會建立大量的線程,從而致使OOM。
    在這裏插入圖片描述

05.線程池的拒絕策略

等待隊列已經排滿了,再也塞不下新任務了同時,
線程池中的max線程也達到頁,沒法繼續爲新任務服務。
這個是時候咱們就須要拒絕策略機制合理的處理這個問題。

06.四大函數式接口

在這裏插入圖片描述
在這裏插入圖片描述

06.Stream流式計算

流(Stream)究竟是什麼呢?
是數據渠道,r用於操做數據源(集合、數組等)所生成的元素序列。

「集合講的是數據,流講的是計算!」

Stream本身不會存儲元素,Stream不會改變源對象。

相反他們會返回一個持有結果的新Stream。

Stream操做是延遲執行的。

這意味着他們會等到須要結果的時候才執行。

建立一個Stream: 一個數據源(數組、集合)

中間操做:一箇中間操做,處理數據源數據

終止操做:一個終止操做,執行中間操做鏈,產生結果

源頭=>中間流水線=>結果
package Part5;import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;import org.w3c.dom.ls.LSOutput;import java.util.Arrays;import java.util.List;public class StreamDemo1 {
    public static void main(String[] args) {
        User u1 = new User(11,"a",23);
        User u2 = new User(12,"b",24);
        User u3 = new User(13,"c",22);
        User u4 = new User(14,"d",28);
        User u5 = new User(16,"e",26);

        List<User> list = Arrays.asList(u1,u2,u3,u4,u5);

        list.stream().filter(t->{return t.getId()%2 == 0;})
                .filter(t->{return t.getAge()>24;})
                .map(m->{return m.getName().toUpperCase();})
                .sorted((o1,o2)->{return o2.compareTo(o1);}).limit(1)
                .forEach(System.out::println);
    }}

07.分支合併框架

java.lang.Object 
java.util.concurrent.AbstractExecutorService 
java.util.concurrent.ForkJoinPool
java.util.concurrent.ForkJoinTask<V> java.util.concurrent.RecursiveTask<V> //遞歸抽象類

在這裏插入圖片描述

package Part5;import java.util.concurrent.ExecutionException;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.ForkJoinTask;import java.util.concurrent.RecursiveTask;class MyTask extends RecursiveTask<Integer>{//資源類,RecursiveTask抽象類爲遞歸

    private static final Integer ADD_VALUE = 10;
    private int begin;
    private int end;
    private int result;

    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if((end-begin)<=ADD_VALUE){
            for(int i=begin;i<=end;i++){
                result = result + i;
            }
        }else{
            int middle = (end+begin)/2;
            MyTask task1 = new MyTask(begin,middle);
            MyTask task2 = new MyTask(middle+1,end);
            task1.fork();//分
            task2.fork();//分支
            result = task1.join()+task2.join();//合併結果
        }
        return result;
    }}public class ForkJoinDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyTask myTask = new MyTask(0,100);
        ForkJoinPool threadPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = threadPool.submit(myTask);//提交任務
        System.out.println(forkJoinTask.get());//獲取結果
        threadPool.shutdown() ;

    }}

08.異步回調(CompletableFuture)

java.lang.Object 
java.util.concurrent.CompletableFuture<T>

測試:

package Part5;import java.util.concurrent.CompletableFuture;import java.util.concurrent.ExecutionException;public class CompletableFutrueDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {


        CompletableFuture<Void>  completableFuture = CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread().getName()+"沒有返回值!");
        });
        completableFuture.get();



        //異步回調
        CompletableFuture<Integer>  completableFuture2 = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName()+"有返回值!");
            int f = 5/0;
            return 1;
        });
        completableFuture2.whenComplete((t,u)->{//正常時的狀況
            System.out.println("***:"+t);
        }).exceptionally(f->{//異常時狀況
            System.out.println("***excption:"+f.getMessage());
            return 444;
        });
    }}

在這裏插入圖片描述

Don’t look forward to tomorrow, don’t miss yesterday, to grasp today.

在這裏插入圖片描述
在這裏插入圖片描述

相關文章
相關標籤/搜索