首頁 > Java > Java基礎 > 主體

java線程池詳解

angryTom
發布: 2019-11-26 15:44:48
轉載
3376 人瀏覽過

java線程池詳解

執行緒池概述

#1. 執行緒池就是一個管理執行緒的池子,可以降低建立和銷毀線程帶來的資源消耗

因為執行緒其實也是一個對象,創建一個對象,需要經過類別載入過程,銷毀一個對象,需要走GC垃圾回收流程,都是需要資源開銷的。

2. 提高響應速度,任務到達了相對於從線程池取線程,自己創建線程肯定慢很多

3. 重複利用,線程用完了再放回池子,達到了重複利用的效果

(推薦影片:java影片教學

#執行緒池執行

##打個比喻

核心執行緒比喻為公司正式員工

非核心執行緒比喻外包員工

阻塞佇列比喻為需求池

提交任務比喻為外包員工

#阻斷佇列比喻為需求池

java線程池詳解提交任務比喻為提需求

正式執行

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,
   BlockingQueue<Runnable> workQueue,
   ThreadFactory threadFactory,
   RejectedExecutionHandler handler)
登入後複製
corePoolSize     核心线程数
maximumPoolSize  线程池最大线程数
keepAliveTime    空闲线程存活时间
TimeUnit         线程空闲存活时间单位
workQueue        存放任务的阻塞队列
threadFactory    线程工厂
handler          饱和策略
登入後複製

● 提交一個任務,執行緒池裡存活的核心執行緒數小於執行緒數corePoolSize時,執行緒池會建立一個核心執行緒去處理提交的任務。

● 如果執行緒池核心執行緒數已滿,也就是執行緒數已經等於corePoolSize,一個新提交的任務,會被放進任務佇列workQueue排隊等待執行。

● 當執行緒池裡面存活的執行緒數已經等於corePoolSize了,並且任務佇列workQueue也滿,判斷執行緒數是否達到maximumPoolSize,即最大執行緒數是否已滿,如果沒到達,建立一個非核心執行緒執行提交的任務。

● 如果目前的執行緒數達到了maximumPoolSize,還有新的任務過來的話,直接採用拒絕策略處理。

幾種飽和策略

AbortPolicy         抛出一个异常,默认的
DiscardPolicy       直接丢弃任务
DiscardOldestPolicy 丢弃队列里最老的任务,将当前这个任务继续提交给线程池
CallerRunsPolicy    交给线程池调用所在的线程进行处理
登入後複製

執行緒池異常處理

由於在執行緒池呼叫執行緒處理任務過程中出現的異常可能會被線程池捕獲,所以對於任務的執行可能是無感知的,因此我們需要考慮線程池異常情況。

方法一:

@Test
public void test1() throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 5; i++) {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("name: " + Thread.currentThread().getName());
                    Object a = null;
                    System.out.println(a.hashCode());
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        });
    }
}
登入後複製
方法二:
@Test
public void test2() throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 20; i++) {
        Future<?> future = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("name: " + Thread.currentThread().getName());
                Object a = null;
                System.out.println(a.hashCode());
            }
        });
        try {
            future.get();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
登入後複製

#執行緒池的工作佇列

##● ArrayBlockingQueue

● LinkedBlockingQueue

● SynchronousQueue

● DelayQueue

● PriorityBlockingQueue

==ArrayBlockingQueue==

##遇到一定容量的數組

##問題組

#● 使用重入鎖,預設使用非公平鎖,入隊和出隊共用一個鎖,互斥

● 是有界設計,如果容量滿無法繼續添加元素直至有元素被移除

● 使用時開闢一段連續的內存,如果初始化容量過大容易造成資源浪費,過小易添加失敗

==LinkedBlockingQueue==

#● 使用鍊錶資料結構

● 非連續性記憶體空間

● 使用兩個重入鎖定分別控制元素的入隊和出隊,並用Condition進行執行緒間的喚醒和等待

● 有邊界的,在預設建構方法中容量是Integer.MAX_VALUE

#==SynchronousQueue==

● 內部容量是0

● 每次刪除操作都要等待插入操作

● 每次插入操作都要等待刪除操作

● 一個元素,一旦有了插入線程和移除線程,那麼很快就由插入線程移交給移除線程,這個容器相當於通道,本身不儲存元素

● 在多任務佇列,是最快的處理任務方式。

==PriorityBlockingQueue==

● 無邊界設計,但容量實際上是依賴系統資源影響

##● 添加元素,如果超過1,則進入優先級排序

==DelayQueue==

● 無邊界設計

● 新增(put)不阻塞,移除阻塞

● 元素都有一個過期時間

● 取元素只有過期的才會被取出

常用的執行緒池

● newFixedThreadPool (固定數目執行緒的執行緒池)

● newCachedThreadPool (可快取執行緒的執行緒池)

● newSingleThreadExecutor (單一執行緒的執行緒池)

● newScheduledThreadPool (定時與週期執行的執行緒池)#● newScheduledThreadPool (定時與週期執行的執行緒池)

#● newScheduledThreadPool (定時與週期執行的執行緒池)

##==newFixedThreadPool==

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

特點

#1.核心執行緒數和最大執行緒數大小一樣2. 沒有所謂的非空閒時間,即keepAliveTime為0

3. 阻塞佇列為無界佇列LinkedBlockingQueuejava線程池詳解

工作機制:

● 提交任務#########● 如果執行緒數少於核心線程,建立核心執行任務######● 如果執行緒數等於核心執行緒,把任務加入LinkedBlockingQueue阻塞佇列## #

● 如果线程执行完任务,去阻塞队列取任务,继续执行。

==newCachedThreadPool==

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
登入後複製

线程池特点

● 核心线程数为0

● 最大线程数为Integer.MAX_VALUE

● 阻塞队列是SynchronousQueue

● 非核心线程空闲存活时间为60秒

java線程池詳解

工作机制:

● 提交任务

● 因为没有核心线程,所以任务直接加到SynchronousQueue队列。

● 判断是否有空闲线程,如果有,就去取出任务执行。

● 如果没有空闲线程,就新建一个线程执行。

● 执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁。

使用场景

用于并发执行大量短期的小任务。

使用SynchronousQueue作为工作队列,工作队列本身并不限制待执行的任务的数量。但此时需要限定线程池的最大大小为一个合理的有限值,而不是Integer.MAX_VALUE,否则可能导致线程池中的工作者线程的数量一直增加到系统资源所无法承受为止。

如果应用程序确实需要比较大的工作队列容量,而又想避免无界工作队列可能导致的问题,不妨考虑SynchronousQueue。SynchronousQueue实现上并不使用缓存空间

==newSingleThreadExecutor==

线程池特点

● 核心线程数为1

● 最大线程数也为1

● 阻塞队列是LinkedBlockingQueue

● keepAliveTime为0

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}
登入後複製

工作机制

java線程池詳解

● 提交任务

● 线程池是否有一条线程在,如果没有,新建线程执行任务

● 如果有,讲任务加到阻塞队列

● 当前的唯一线程,从队列取任务,执行完一个,再继续取,一个人(一条线程)夜以继日地干活。

使用场景

适用于串行执行任务的场景,一个任务一个任务的执行

==newScheduledThreadPool==

线程池特点

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}
登入後複製

● 最大线程数为Integer.MAX_VALUE

● 阻塞队列是DelayedWorkQueue

● keepAliveTime为0

● scheduleAtFixedRate() :按某种速率周期执行

● scheduleWithFixedDelay():在某个延迟后执行

工作机制

● 添加一个任务

● 线程池中的线程从 DelayQueue 中取任务

● 线程从 DelayQueue 中获取 time 大于等于当前时间的task

● 执行完后修改这个 task 的 time 为下次被执行的时间

● 这个 task 放回DelayQueue队列中

scheduleWithFixedDelay

● 无论任务执行时间长短,都是当第一个任务执行完成之后,延迟指定时间再开始执行第二个任务

scheduleAtFixedRate

● 在任务执行时间小于间隔时间的情况下,程序以起始时间为准则,每隔指定时间执行一次,不受任务执行时间影响

● 当执行任务时间大于间隔时间,此方法不会重新开启一个新的任务进行执行,而是等待原有任务执行完成,马上开启下一个任务进行执行。此时,执行间隔时间已经被打乱

本文来自php中文网,java教程栏目,欢迎学习!

以上是java線程池詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:cnblogs.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!