最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 線程池詳解及創(chuàng)建簡單實例

 更新時間:2017年02月04日 15:38:20   投稿:lqh  
這篇文章主要介紹了Java 線程池詳解及創(chuàng)建簡單實例的相關資料,需要的朋友可以參考下

Java 線程池

最近在改進項目的并發(fā)功能,但開發(fā)起來磕磕碰碰的??戳撕枚噘Y料,總算加深了認識。于是打算配合查看源代碼,總結并發(fā)編程的原理。

準備從用得最多的線程池開始,圍繞創(chuàng)建、執(zhí)行、關閉認識線程池整個生命周期的實現(xiàn)原理。后續(xù)再研究原子變量、并發(fā)容器、阻塞隊列、同步工具、鎖等等主題。java.util.concurrent里的并發(fā)工具用起來不難,但不能僅僅會用,我們要read the fucking source code,哈哈。順便說聲,我用的JDK是1.8。

Executor框架

Executor是一套線程池管理框架,接口里只有一個方法execute,執(zhí)行Runnable任務。ExecutorService接口擴展了Executor,添加了線程生命周期的管理,提供任務終止、返回任務結果等方法。AbstractExecutorService實現(xiàn)了ExecutorService,提供例如submit方法的默認實現(xiàn)邏輯。

然后到今天的主題ThreadPoolExecutor,繼承了AbstractExecutorService,提供線程池的具體實現(xiàn)。

構造方法

下面是ThreadPoolExecutor最普通的構造函數(shù),最多有七個參數(shù)。具體代碼不貼了,只是一些參數(shù)校驗和設置的語句。

public ThreadPoolExecutor(int corePoolSize,
               int maximumPoolSize,
               long keepAliveTime,
               TimeUnit unit,
               BlockingQueue<Runnable> workQueue,
               ThreadFactory threadFactory,
               RejectedExecutionHandler handler) {
  }

corePoolSize是線程池的目標大小,即是線程池剛剛創(chuàng)建起來,還沒有任務要執(zhí)行時的大小。maximumPoolSize是線程池的最大上限。keepAliveTime是線程的存活時間,當線程池內的線程數(shù)量大于corePoolSize,超出存活時間的空閑線程就會被回收。unit就不用說了,剩下的三個參數(shù)看后文的分析。

預設的定制線程池

ThreadPoolExecutor預設了一些已經(jīng)定制好的線程池,由Executors里的工廠方法創(chuàng)建。下面分析newSingleThreadExecutor、newFixedThreadPool、newCachedThreadPool的創(chuàng)建參數(shù)。

newFixedThreadPool

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

newFixedThreadPool的corePoolSize和maximumPoolSize都設置為傳入的固定數(shù)量,keepAliveTim設置為0。線程池創(chuàng)建后,線程數(shù)量將會固定不變,適合需要線程很穩(wěn)定的場合。

newSingleThreadExecutor

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

newSingleThreadExecutor是線程數(shù)量固定為1的newFixedThreadPool版本,保證池內的任務串行。注意到返回的是FinalizableDelegatedExecutorService,來看看源碼:

static class FinalizableDelegatedExecutorService
    extends DelegatedExecutorService {
    FinalizableDelegatedExecutorService(ExecutorService executor) {
      super(executor);
    }
    protected void finalize() {
      super.shutdown();
    }
  }

FinalizableDelegatedExecutorService繼承了DelegatedExecutorService,僅僅在gc時增加關閉線程池的操作,再來看看DelegatedExecutorService的源碼:

static class DelegatedExecutorService extends AbstractExecutorService {
    private final ExecutorService e;
    DelegatedExecutorService(ExecutorService executor) { e = executor; }
    public void execute(Runnable command) { e.execute(command); }
    public void shutdown() { e.shutdown(); }
    public List<Runnable> shutdownNow() { return e.shutdownNow(); }
    public boolean isShutdown() { return e.isShutdown(); }
    public boolean isTerminated() { return e.isTerminated(); }
    //...
  }

代碼很簡單,DelegatedExecutorService包裝了ExecutorService,使其只暴露出ExecutorService的方法,因此不能再配置線程池的參數(shù)。本來,線程池創(chuàng)建的參數(shù)是可以調整的,ThreadPoolExecutor提供了set方法。使用newSingleThreadExecutor目的是生成單線程串行的線程池,如果還能配置線程池大小,那就沒意思了。

Executors還提供了unconfigurableExecutorService方法,將普通線程池包裝成不可配置的線程池。如果不想線程池被不明所以的后人修改,可以調用這個方法。

newCachedThreadPool

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

newCachedThreadPool生成一個會緩存的線程池,線程數(shù)量可以從0到Integer.MAX_VALUE,超時時間為1分鐘。線程池用起來的效果是:如果有空閑線程,會復用線程;如果沒有空閑線程,會新建線程;如果線程空閑超過1分鐘,將會被回收。

newScheduledThreadPool

newScheduledThreadPool將會創(chuàng)建一個可定時執(zhí)行任務的線程池。這個不打算在本文展開,后續(xù)會另開文章細講。

等待隊列

newCachedThreadPool的線程上限幾乎等同于無限,但系統(tǒng)資源是有限的,任務的處理速度總有可能比不上任務的提交速度。因此,可以為ThreadPoolExecutor提供一個阻塞隊列來保存因線程不足而等待的Runnable任務,這就是BlockingQueue。

JDK為BlockingQueue提供了幾種實現(xiàn)方式,常用的有:

  • ArrayBlockingQueue:數(shù)組結構的阻塞隊列
  • LinkedBlockingQueue:鏈表結構的阻塞隊列
  • PriorityBlockingQueue:有優(yōu)先級的阻塞隊列
  • SynchronousQueue:不會存儲元素的阻塞隊列

newFixedThreadPool和newSingleThreadExecutor在默認情況下使用一個無界的LinkedBlockingQueue。要注意的是,如果任務一直提交,但線程池又不能及時處理,等待隊列將會無限制地加長,系統(tǒng)資源總會有消耗殆盡的一刻。所以,推薦使用有界的等待隊列,避免資源耗盡。但解決一個問題,又會帶來新問題:隊列填滿之后,再來新任務,這個時候怎么辦?后文會介紹如何處理隊列飽和。

newCachedThreadPool使用的SynchronousQueue十分有趣,看名稱是個隊列,但它卻不能存儲元素。要將一個任務放進隊列,必須有另一個線程去接收這個任務,一個進就有一個出,隊列不會存儲任何東西。因此,SynchronousQueue是一種移交機制,不能算是隊列。newCachedThreadPool生成的是一個沒有上限的線程池,理論上提交多少任務都可以,使用SynchronousQueue作為等待隊列正合適。

飽和策略

當有界的等待隊列滿了之后,就需要用到飽和策略去處理,ThreadPoolExecutor的飽和策略通過傳入RejectedExecutionHandler來實現(xiàn)。如果沒有為構造函數(shù)傳入,將會使用默認的defaultHandler。

private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
      throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
    }
  }

AbortPolicy是默認的實現(xiàn),直接拋出一個RejectedExecutionException異常,讓調用者自己處理。除此之外,還有幾種飽和策略,來看一下:

 public static class DiscardPolicy implements RejectedExecutionHandler {
    public DiscardPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
  }

DiscardPolicy的rejectedExecution直接是空方法,什么也不干。如果隊列滿了,后續(xù)的任務都拋棄掉。

 public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    public DiscardOldestPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
      if (!e.isShutdown()) {
        e.getQueue().poll();
        e.execute(r);
      }
    }
  }

DiscardOldestPolicy會將等待隊列里最舊的任務踢走,讓新任務得以執(zhí)行。

 public static class CallerRunsPolicy implements RejectedExecutionHandler {
    public CallerRunsPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
      if (!e.isShutdown()) {
        r.run();
      }
    }
  }

最后一種飽和策略是CallerRunsPolicy,它既不拋棄新任務,也不拋棄舊任務,而是直接在當前線程運行這個任務。當前線程一般就是主線程啊,讓主線程運行任務,說不定就阻塞了。如果不是想清楚了整套方案,還是少用這種策略為妙。

ThreadFactory

每當線程池需要創(chuàng)建一個新線程,都是通過線程工廠獲取。如果不為ThreadPoolExecutor設定一個線程工廠,就會使用默認的defaultThreadFactory:

public static ThreadFactory defaultThreadFactory() {
  return new DefaultThreadFactory();
}
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
      SecurityManager s = System.getSecurityManager();
      group = (s != null) ? s.getThreadGroup() :
                 Thread.currentThread().getThreadGroup();
      namePrefix = "pool-" +
             poolNumber.getAndIncrement() +
            "-thread-";
    }

    public Thread newThread(Runnable r) {
      Thread t = new Thread(group, r,
                 namePrefix + threadNumber.getAndIncrement(),
                 0);
      if (t.isDaemon())
        t.setDaemon(false);
      if (t.getPriority() != Thread.NORM_PRIORITY)
        t.setPriority(Thread.NORM_PRIORITY);
      return t;
    }
  }

平時打印線程池里線程的name時,會輸出形如pool-1-thread-1之類的名稱,就是在這里設置的。這個默認的線程工廠,創(chuàng)建的線程是普通的非守護線程,如果需要定制,實現(xiàn)ThreadFactory后傳給ThreadPoolExecutor即可。

不看代碼不總結不會知道,光是線程池的創(chuàng)建就可以引出很多學問。別看平時創(chuàng)建線程池是一句代碼的事,其實ThreadPoolExecutor提供了很靈活的定制方法。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關文章

  • Hibernate Validation自定義注解校驗的實現(xiàn)

    Hibernate Validation自定義注解校驗的實現(xiàn)

    這篇文章主要介紹了Hibernate Validation自定義注解校驗的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • spring boot和spring cloud之間的版本關系

    spring boot和spring cloud之間的版本關系

    這篇文章主要介紹了spring boot和spring cloud之間的版本關系,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • java中int轉string與string轉int的效率對比

    java中int轉string與string轉int的效率對比

    這篇文章主要介紹了java中int轉string與string轉int的效率對比,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java基礎之Object類詳解

    Java基礎之Object類詳解

    這篇文章主要介紹了Java基礎之Object類詳解,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05
  • Java?Web開發(fā)常用框架Spring?MVC?Struts示例解析

    Java?Web開發(fā)常用框架Spring?MVC?Struts示例解析

    這篇文章主要為大家介紹了Java?Web開發(fā)常用框架Spring?MVC?Struts示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Java看完秒懂版熔斷和降級的關系

    Java看完秒懂版熔斷和降級的關系

    這篇文章主要介紹了Java熔斷和降級的關系,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • 淺談Java基于Consul創(chuàng)建分布式鎖

    淺談Java基于Consul創(chuàng)建分布式鎖

    這篇文章主要介紹了淺談基于Consul創(chuàng)建分布式鎖,Consul是HashiCorp公司推出的開源工具,用于實現(xiàn)分布式系統(tǒng)的服務發(fā)現(xiàn)與配置Consul是分布式的、高可用的、可橫向擴展的,需要的朋友可以參考下
    2023-07-07
  • 解決JPA @OneToMany及懶加載無效的問題

    解決JPA @OneToMany及懶加載無效的問題

    這篇文章主要介紹了解決JPA @OneToMany及懶加載無效的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • MyBatis常見報錯問題及解決方案

    MyBatis常見報錯問題及解決方案

    這篇文章主要介紹了MyBatis常見報錯問題及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • java的arrays數(shù)組排序示例分享

    java的arrays數(shù)組排序示例分享

    排序算法,基本的高級語言都有一些提供。C語言有qsort()函數(shù),C++有sort()函數(shù),java語言有Arrays類(不是Array)。用這些排序時,都可以寫自己的排序規(guī)則
    2014-02-02

最新評論

新乐市| 临夏县| 福贡县| 南宫市| 中山市| 金阳县| 安新县| 洛宁县| 定州市| 湖南省| 比如县| 曲沃县| 玉山县| 广河县| 夏河县| 萨嘎县| 定结县| 仁怀市| 靖边县| 紫金县| 苍山县| 拜泉县| 吐鲁番市| 扎赉特旗| 黑龙江省| 阿拉尔市| 武安市| 芦山县| 芜湖市| 高邮市| 葫芦岛市| 瓮安县| 阳新县| 曲沃县| 武宣县| 奎屯市| 张家港市| 扎赉特旗| 三江| 昌乐县| 古田县|