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

java多線程教程之如何使用線程池詳解

 更新時(shí)間:2018年11月03日 14:19:37   作者:shanhm  
這篇文章主要給大家介紹了關(guān)于java多線程之如何使用線程池的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

為什么要用線程池?

諸如 Web 服務(wù)器、數(shù)據(jù)庫服務(wù)器、文件服務(wù)器或郵件服務(wù)器之類的許多服務(wù)器應(yīng)用程序都面臨處理來自某些遠(yuǎn)程來源的大量短小的任務(wù)。請(qǐng)求以某種方式到達(dá)服務(wù)器,這種方式可能是通過網(wǎng)絡(luò)協(xié)議(例如 HTTP、FTP 或 POP)、通過 JMS 隊(duì)列或者可能通過輪詢數(shù)據(jù)庫。不管請(qǐng)求如何到達(dá),服務(wù)器應(yīng)用程序中經(jīng)常出現(xiàn)的情況是:?jiǎn)蝹€(gè)任務(wù)處理的時(shí)間很短而請(qǐng)求的數(shù)目卻是巨大的。

只有當(dāng)任務(wù)都是同類型并且相互獨(dú)立時(shí),線程池的性能才能達(dá)到最佳。如果將運(yùn)行時(shí)間較長(zhǎng)的與運(yùn)行時(shí)間較短的任務(wù)混合在一起,那么除非線程池很大,否則將可能造成擁塞,如果提交的任務(wù)依賴于其他任務(wù),那么除非線程池?zé)o線大,否則將可能造成死鎖。

例如饑餓死鎖:線程池中的任務(wù)需要無限等待一些必須由池中其他任務(wù)才能提供的資源或條件。

ThreadPoolExecutor的通用構(gòu)造函數(shù):(在調(diào)用完構(gòu)造函數(shù)之后可以繼續(xù)定制ThreadPoolExecutor)

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

飽和策略:

ThreadPoolExecutor允許提供一個(gè)BlockingQueue來保存等待執(zhí)行的任務(wù)。

當(dāng)有界隊(duì)列被填滿后,飽和策略開始發(fā)揮作用??梢酝ㄟ^調(diào)用setRejectedExecutionHandler來修改。

中止是默認(rèn)的飽和策略,該策略將拋出未檢查的RejectedExecutionException,調(diào)用者可以捕獲這個(gè)異常,然后根據(jù)需求編寫自己的處理代碼。

調(diào)用者運(yùn)行策略實(shí)現(xiàn)了一種調(diào)節(jié)機(jī)制,該策略既不會(huì)拋棄任務(wù),也不會(huì)拋出異常,而是將某些任務(wù)回退到調(diào)用者,從而降低新任務(wù)的流量。

例如對(duì)于WebServer,當(dāng)線程池中的所有線程都被占用,并且工作隊(duì)列被填滿后,下一個(gè)任務(wù)在調(diào)用execute時(shí)在主線程中執(zhí)行。

由于執(zhí)行任務(wù)需要一定的時(shí)間,因此主線程至少在一段時(shí)間內(nèi)不能提交任何任務(wù),從而使得工作者線程有時(shí)間來處理完正在執(zhí)行的任務(wù)。

在這期間,主線程不會(huì)調(diào)用accept,因此到達(dá)的請(qǐng)求將被保存在TCP層的隊(duì)列中而不是在應(yīng)用程序的隊(duì)列中,如果持續(xù)過載,那么TCP層最終發(fā)現(xiàn)它的請(qǐng)求隊(duì)列被填滿,同樣會(huì)開始拋棄請(qǐng)求。

因此當(dāng)服務(wù)器過載時(shí),這種過載會(huì)逐漸向外蔓延開來---從線程池到工作隊(duì)列到應(yīng)用程序再到TCP層,最終到達(dá)客戶端,導(dǎo)致服務(wù)器在高負(fù)載下實(shí)現(xiàn)一種平緩的性能降低。

exec.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

當(dāng)工作隊(duì)列被填滿后,沒有預(yù)定于的飽和策略來阻塞execute。而通過Semaphore來現(xiàn)在任務(wù)的到達(dá)率,可以實(shí)現(xiàn)。

/**
 * 設(shè)置信號(hào)量的上界設(shè)置為線程池的大小加上可排隊(duì)任務(wù)的數(shù)量,控制正在執(zhí)行和等待執(zhí)行的任務(wù)數(shù)量。
 */
public class BoundedExecutor {
 
 private final Executor exec;
 private final Semaphore semaphore;
 
 public BoundedExecutor(Executor exec,int bound){
  this.exec = exec;
  this.semaphore = new Semaphore(bound);
 }
 
 public void submitTask(final Runnable task) throws InterruptedException{
  semaphore.acquire();
  try{
   exec.execute(new Runnable(){
    public void run(){
     try{
      task.run();
     }finally{
      semaphore.release();
     }
    }
   });
  }catch(RejectedExecutionException e){
   semaphore.release();
  }
 }
}

線程工廠

線程池配置信息中可以定制線程工廠,在ThreadFactory中只定義了一個(gè)方法newThread,每當(dāng)線程池需要?jiǎng)?chuàng)建一個(gè)新線程時(shí)都會(huì)調(diào)用這個(gè)方法。

public interface ThreadFactory{
 Thread newThread(Runnable r);
}
// 示例:將一個(gè)特定于線程池的名字傳遞給MyThread的構(gòu)造函數(shù),從而可以再線程轉(zhuǎn)儲(chǔ)和錯(cuò)誤日志信息中區(qū)分來自不同線程池的線程。
 public class MyThreadFactory implements ThreadFactory{
 
 private final String poolName;
 
 public MyThreadFactory(String poolName){
  this.poolName = poolName;
 }
 
 public Thread newThread(Runnable runnable){
  return new MyThread(runnable,poolName);
 }
}
// 示例:為線程指定名字,設(shè)置自定義UncaughtExceptionHandler向Logger中寫入信息及維護(hù)一些統(tǒng)計(jì)信息以及在線程被創(chuàng)建或者終止時(shí)把調(diào)試消息寫入日志。
public class MyThread extends Thread{
 public static final String default_name = "myThread";
 private static volatile boolean debugLifecycle = false;
 private static final AtomicInteger created = new AtomicInteger();
 private static final AtomicInteger alive = new AtomicInteger();
 private static final Logger log = Logger.getAnonymousLogger();

 public MyThread(Runnable runnable){
  this(runnable,default_name);
 }

 public MyThread(Runnable runnable, String defaultName) {
  super(runnable,defaultName + "-" + created.incrementAndGet());
  setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
   @Override
   public void uncaughtException(Thread t, Throwable e) {
    log.log(Level.SEVERE,"uncaught in thread " + t.getName(), e); 

   }
  });
 }

 public void run(){
  boolean debug = debugLifecycle;
  if(debug){
   log.log(Level.FINE,"created " + getName());
  }
  try{
   alive.incrementAndGet();
   super.run();
  }finally{
   alive.decrementAndGet();
   if(debug){
    log.log(Level.FINE,"Exiting " + getName());
   }
  }

 }
}

擴(kuò)展ThreadPoolExecutor

在線程池完成關(guān)閉操作時(shí)調(diào)用terminated,也就是在所有任務(wù)都已經(jīng)完成并且所有工作者線程也已經(jīng)關(guān)閉后。terminated可以用來釋放Executor在其生命周期里分配的各種資源,此外還可以執(zhí)行發(fā)送通知、記錄日志或者收集finalize統(tǒng)計(jì)信息等操作。

示例:給線程池添加統(tǒng)計(jì)信息

/**
 * TimingThreadPool中給出了一個(gè)自定義的線程池,通過beforeExecute、afterExecute、terminated等方法來添加日志記錄和統(tǒng)計(jì)信息收集。
 * 為了測(cè)量任務(wù)的運(yùn)行時(shí)間,beforeExecute必須記錄開始時(shí)間并把它保存到一個(gè)afterExecute可用訪問的地方。
 * 因?yàn)檫@些方法將在執(zhí)行任務(wù)的線程中調(diào)用,因此beforeExecute可以把值保存到一個(gè)ThreadLocal變量中。然后由afterExecute來取。
 * 在TimingThreadPool中使用了兩個(gè)AtomicLong變量,分別用于記錄已處理的任務(wù)和總的處理時(shí)間,并通過包含平均任務(wù)時(shí)間的日志消息。
 */
public class TimingThreadPool extends ThreadPoolExecutor{
 
 public TimingThreadPool(int corePoolSize, int maximumPoolSize,
   long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
  super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
 }
 
 private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
 private final Logger log = Logger.getLogger("TimingThreadPool");
 private final AtomicLong numTasks = new AtomicLong();
 private final AtomicLong totalTime = new AtomicLong();
 
 protected void beforeExecute(Thread t,Runnable r){
  super.beforeExecute(t, r);
  log.fine(String.format("Thread %s: start %s", t,r));
  startTime.set(System.nanoTime());
 }
 
 protected void afterExecute(Throwable t,Runnable r){
  try{
   long endTime = System.nanoTime();
   long taskTime = endTime - startTime.get();
   numTasks.incrementAndGet();
   totalTime.addAndGet(taskTime);
   log.fine(String.format("Thread %s: end %s, time=%dns", t,r,taskTime));
  }finally{
   super.afterExecute(r, t);
  }
 }
 
 protected void terminated(){
  try{
   log.info(String.format("Terminated: avg time=%dns", totalTime.get()/numTasks.get()));
  }finally{
   super.terminated();
  }
 }
}

#筆記內(nèi)容參考  《java并發(fā)編程實(shí)戰(zhàn)》

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • springboot整合日志處理Logback的實(shí)現(xiàn)示例

    springboot整合日志處理Logback的實(shí)現(xiàn)示例

    Logback是由log4j創(chuàng)始人設(shè)計(jì)的又一個(gè)開源日志組件,本文主要介紹了springboot整合日志處理Logback,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • 入門到精通Java?SSO單點(diǎn)登錄原理詳解

    入門到精通Java?SSO單點(diǎn)登錄原理詳解

    這篇文章主要介紹了入門到精通Java?SSO單點(diǎn)登錄原理詳解,本文主要對(duì)SSO單點(diǎn)登錄與CAS、OAuth2.0兩種授權(quán)協(xié)議的關(guān)系和原理進(jìn)行詳細(xì)說明
    2022-09-09
  • SpringBoot封裝響應(yīng)數(shù)據(jù)實(shí)現(xiàn)過程詳解

    SpringBoot封裝響應(yīng)數(shù)據(jù)實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了SpringBoot封裝響應(yīng)數(shù)據(jù)實(shí)現(xiàn)過程,SpringBoot響應(yīng)數(shù)據(jù)封裝是指在SpringBoot應(yīng)用程序中,將返回的數(shù)據(jù)進(jìn)行封裝,以便于前端頁面或其他客戶端使用,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • idea編輯XML文件出現(xiàn):Tag name expected報(bào)錯(cuò)的解決

    idea編輯XML文件出現(xiàn):Tag name expected報(bào)錯(cuò)的解決

    在XML中,一些特殊字符不能直接使用,因?yàn)樗鼈儽槐A粲糜赬ML文檔的結(jié)構(gòu)和語法,如果直接使用這些保留字符,會(huì)導(dǎo)致解析錯(cuò)誤,正確的做法是使用實(shí)體引用或字符引用,或者使用CDATA標(biāo)記將這些字符包裹起來
    2025-01-01
  • spring初始化方法的執(zhí)行順序及其原理分析

    spring初始化方法的執(zhí)行順序及其原理分析

    這篇文章主要介紹了spring初始化方法的執(zhí)行順序及其原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Hibernate原理及應(yīng)用

    Hibernate原理及應(yīng)用

    本文主要介紹了Hibernate原理及應(yīng)用。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • Java實(shí)現(xiàn)默認(rèn)目錄查看與修改的方法

    Java實(shí)現(xiàn)默認(rèn)目錄查看與修改的方法

    本項(xiàng)目介紹了Java如何獲取和修改默認(rèn)目錄,并通過示例代碼展示了如何在默認(rèn)目錄下創(chuàng)建和操作文件,盡管Java無法直接更改全局默認(rèn)目錄,但可以通過System.setProperty間接影響部分API的默認(rèn)行為,需要的朋友可以參考下
    2025-03-03
  • java查詢近七日數(shù)據(jù)功能的實(shí)現(xiàn)

    java查詢近七日數(shù)據(jù)功能的實(shí)現(xiàn)

    這篇文章主要介紹了java查詢近七日數(shù)據(jù)功能的實(shí)現(xiàn),文章內(nèi)容詳細(xì),簡(jiǎn)單易懂,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2023-01-01
  • 微信支付java版本之JSAPI支付+發(fā)送模板消息

    微信支付java版本之JSAPI支付+發(fā)送模板消息

    這篇文章主要介紹了微信支付java版本之JSAPI支付,發(fā)送模板消息,感興趣的小伙伴們可以參考一下
    2016-08-08
  • java求數(shù)組最大值和最小數(shù)示例分享

    java求數(shù)組最大值和最小數(shù)示例分享

    這篇文章主要介紹了java求數(shù)組最大值和最小數(shù)示例,需要的朋友可以參考下
    2014-03-03

最新評(píng)論

神池县| 乌鲁木齐县| 大余县| 孟村| 玉溪市| 满城县| 肥东县| 盐源县| 裕民县| 凤城市| 湘西| 义乌市| 罗定市| 武乡县| 和硕县| 双鸭山市| 惠东县| 光山县| 江北区| 吉木萨尔县| 松原市| 健康| 交口县| 曲水县| 五大连池市| 太仆寺旗| 苗栗县| 务川| 新田县| 宁都县| 阿坝| 武城县| 宿迁市| 临武县| 招远市| 桑日县| 延吉市| 宜宾县| 徐水县| 阳春市| 孝义市|