天天看點

二、JUC之線程池二、JUC之線程池

二、JUC之線程池

二、JUC之線程池

  • 二、JUC之線程池
      • 1、為什麼用線程池
      • 2、線程池的使用
        • 1、Executors.newFixedThreadPool(int)
        • 2、Executors.newSingleThreadExecutor()
        • 3、Executors.newCachedThreadPool()
      • 3、ThreadPoolExecutor底層原理
      • 4、拒絕政策?生産中如設定合理參數
        • 1、線程池的拒絕政策
        • 2、JDK内置的拒絕政策
      • 5、超級大坑 在工作中單一的/固定數的/可變的三種建立線程池的方法哪個用的多?
      • 6、自定義線程池
      • 7、BlockingQueue阻塞隊列
        • 1、棧與隊列
        • 2、阻塞隊列
        • 3、種類分析
        • 4、BlockingQueue核心方法
      • 更多内容:

1、為什麼用線程池

線程池的優勢:

​ 線程池做的工作主要是控制運作的線程數量,處理過程中将任務放入隊列,然後線上程建立後啟動這些任務,如果線程數量超過了最大數量,超出數量的線程排隊等候,等其他線程執行完畢,再從隊列中取出任務來執行。

它的主要特點為:線程複用;控制最大并發數;管理線程。

第一:降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的銷耗。

第二:提高響應速度。當任務到達時,任務可以不需要等待線程建立就能立即執行。

第三:提高線程的可管理性。線程是稀缺資源,如果無限制的建立,不僅會銷耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的配置設定,調優和監控

2、線程池的使用

1、Executors.newFixedThreadPool(int)

​ newFixedThreadPool建立的線程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue執行長期任務性能好,建立一個線程池,一池有N個固定的線程,有固定線程數的線程

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
           

2、Executors.newSingleThreadExecutor()

​ newSingleThreadExecutor 建立的線程池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue一個任務一個任務的執行,一池一線程

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
           

3、Executors.newCachedThreadPool()

​ newCachedThreadPool建立的線程池将corePoolSize設定為0,将maximumPoolSize設定為Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是說來了任務就建立線程運作,當線程空閑超過60秒,就銷毀線程。

執行很多短期異步任務,線程池根據需要建立新線程,但在先前建構的線程可用時将重用它們。可擴容,遇強則強

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
           
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 線程池
 * Arrays
 * Collections
 * Executors
 */
public class MyThreadPoolDemo {

    public static void main(String[] args) {
        //List list = new ArrayList();
        //List list = Arrays.asList("a","b");
        //固定數的線程池,一池五線程

//       ExecutorService threadPool =  Executors.newFixedThreadPool(5); //一個銀行網點,5個受理業務的視窗
//       ExecutorService threadPool =  Executors.newSingleThreadExecutor(); //一個銀行網點,1個受理業務的視窗
       ExecutorService threadPool =  Executors.newCachedThreadPool(); //一個銀行網點,可擴充受理業務的視窗

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

    }
}
           

3、ThreadPoolExecutor底層原理

二、JUC之線程池二、JUC之線程池
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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
           
  1. corePoolSize:線程池中的常駐核心線程數
  2. maximumPoolSize:線程池中能夠容納同時執行的最大線程數,此值必須大于等于1
  3. keepAliveTime:多餘的空閑線程的存活時間,目前池中線程數量超過corePoolSize時,當空閑時間,達到keepAliveTime時,多餘線程會被銷毀直到隻剩下corePoolSize個線程為止
  4. unit:keepAliveTime的機關
  5. workQueue:任務隊列,被送出但尚未被執行的任務
  6. threadFactory:表示生成線程池中工作線程的線程工廠,用于建立線程,一般預設的即可
  7. handler:拒絕政策,表示當隊列滿了,并且工作線程大于等于線程池的最大線程數(maximumPoolSize)時如何來拒絕請求執行的runnable的政策
二、JUC之線程池二、JUC之線程池
二、JUC之線程池二、JUC之線程池
1、在建立了線程池後,開始等待請求。
2、當調用execute()方法添加一個請求任務時,線程池會做出如下判斷:
  2.1如果正在運作的線程數量小于corePoolSize,那麼馬上建立線程運作這個任務;
  2.2如果正在運作的線程數量大于或等于corePoolSize,那麼将這個任務放入隊列;
  2.3如果這個時候隊列滿了且正在運作的線程數量還小于maximumPoolSize,那麼還是要建立非核心線程立刻運作這個任務;
  2.4如果隊列滿了且正在運作的線程數量大于或等于maximumPoolSize,那麼線程池會啟動飽和拒絕政策來執行。
3、當一個線程完成任務時,它會從隊列中取下一個任務來執行。
4、當一個線程無事可做超過一定的時間(keepAliveTime)時,線程會判斷:
    如果目前運作的線程數大于corePoolSize,那麼這個線程就被停掉。
    是以線程池的所有任務完成後,它最終會收縮到corePoolSize的大小。
           

4、拒絕政策?生産中如設定合理參數

1、線程池的拒絕政策

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

2、JDK内置的拒絕政策

AbortPolicy(預設):直接抛出RejectedExecutionException異常阻止系統正常運作

CallerRunsPolicy:“調用者運作”一種調節機制,該政策既不會抛棄任務,也不會抛出異常,而是将某些任務回退到調用者,進而降低新任務的流量。

DiscardOldestPolicy:抛棄隊列中等待最久的任務,然後把目前任務加入隊列中嘗試再次送出目前任務。

DiscardPolicy:該政策默默地丢棄無法處理的任務,不予任何處理也不抛出異常。如果允許任務丢失,這是最好的一種政策。

以上内置拒絕政策均實作了RejectedExecutionHandle接口

5、超級大坑 在工作中單一的/固定數的/可變的三種建立線程池的方法哪個用的多?

答案是一個都不用,我們工作中隻能使用自定義的

二、JUC之線程池二、JUC之線程池

6、自定義線程池

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * 線程池
 * Arrays
 * Collections
 * Executors
 */
public class MyThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                //new ThreadPoolExecutor.AbortPolicy()
                //new ThreadPoolExecutor.CallerRunsPolicy()
                //new ThreadPoolExecutor.DiscardOldestPolicy()
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        //10個顧客請求
        try {
            for (int i = 1; i <= 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t 辦理業務");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }

    }

    private static void threadPool() {
        //List list = new ArrayList();
        //List list = Arrays.asList("a","b");
        //固定數的線程池,一池五線程

//       ExecutorService threadPool =  Executors.newFixedThreadPool(5); //一個銀行網點,5個受理業務的視窗
//       ExecutorService threadPool =  Executors.newSingleThreadExecutor(); //一個銀行網點,1個受理業務的視窗
        ExecutorService threadPool = Executors.newCachedThreadPool(); //一個銀行網點,可擴充受理業務的視窗

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

7、BlockingQueue阻塞隊列

1、棧與隊列

棧:先進後出,後進先出

隊列:先進先出

2、阻塞隊列

阻塞:必須要阻塞/不得不阻塞

二、JUC之線程池二、JUC之線程池

線程1往阻塞隊列裡添加元素,線程2從阻塞隊列裡移除元素

當隊列是空的,從隊列中擷取元素的操作将會被阻塞

當隊列是滿的,從隊列中添加元素的操作将會被阻塞

試圖從空的隊列中擷取元素的線程将會被阻塞,直到其他線程往空的隊列插入新的元素

試圖向已滿的隊列中添加新元素的線程将會被阻塞,直到其他線程從隊列中移除一個或多個元素或者完全清空,使隊列變得空閑起來并後續新增

二、JUC之線程池二、JUC之線程池

3、種類分析

ArrayBlockingQueue:由數組結構組成的有界阻塞隊列。

LinkedBlockingQueue:由連結清單結構組成的有界(但大小預設值為integer.MAX_VALUE)阻塞隊列。

PriorityBlockingQueue:支援優先級排序的無界阻塞隊列。

DelayQueue:使用優先級隊列實作的延遲無界阻塞隊列。

SynchronousQueue:不存儲元素的阻塞隊列,也即單個元素的隊列。

LinkedTransferQueue:由連結清單組成的無界阻塞隊列。

LinkedBlockingDeque:由連結清單組成的雙向阻塞隊列。

4、BlockingQueue核心方法

二、JUC之線程池二、JUC之線程池
二、JUC之線程池二、JUC之線程池
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 阻塞隊列
 */
public class BlockingQueueDemo {

    public static void main(String[] args) throws InterruptedException {

//        List list = new ArrayList();

        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);
        //第一組
//        System.out.println(blockingQueue.add("a"));
//        System.out.println(blockingQueue.add("b"));
//        System.out.println(blockingQueue.add("c"));
//        System.out.println(blockingQueue.element());

        //System.out.println(blockingQueue.add("x"));
//        System.out.println(blockingQueue.remove());
//        System.out.println(blockingQueue.remove());
//        System.out.println(blockingQueue.remove());
//        System.out.println(blockingQueue.remove());
//    第二組
//        System.out.println(blockingQueue.offer("a"));
//        System.out.println(blockingQueue.offer("b"));
//        System.out.println(blockingQueue.offer("c"));
//        System.out.println(blockingQueue.offer("x"));
//        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.poll());
//    第三組        
//         blockingQueue.put("a");
//         blockingQueue.put("b");
//         blockingQueue.put("c");
//         //blockingQueue.put("x");
//        System.out.println(blockingQueue.take());
//        System.out.println(blockingQueue.take());
//        System.out.println(blockingQueue.take());
//        System.out.println(blockingQueue.take());
        
//    第四組        
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        System.out.println(blockingQueue.offer("a",3L, TimeUnit.SECONDS));

    }
}
           

下一篇:CompletableFuture

更多内容:

更多内容大家可以關注一下個人部落格網,https://blog.xueqimiao.com/,内容更豐富喔。

二、JUC之線程池二、JUC之線程池

回複JUC可以擷取完整md文檔喔,謝謝關注。