Java中的線程池和作用,有必要了解一下

在Java開發(fā)中蔑担,多線程執(zhí)行任務(wù)是很常見的露氮,Java也提供了線程類Thread來讓我們方便創(chuàng)建一個線程如下代碼所示

           new Thread(){
                @Override
                public void run() {
                    .....

                }
            }.start();

  • 這樣創(chuàng)建新的線程有幾個缺點

    • 每次要開啟新的線程都需要創(chuàng)建一個,性能差
    • 線程隨意創(chuàng)建钟沛,缺乏統(tǒng)一的管理
    • 不能做到線程的中斷
  • 處理上面的這些問題畔规,我們就需要使用線程池來管理線程。

Java SE5d的java.util.concurrent包 提供了Executor(執(zhí)行器)來管理線程對象恨统。Executor是一個接口叁扫,而ExecutorService繼承了Excutor接口三妈,ExecutorService是一個具有生命周期的Executor,它知道如何構(gòu)建恰當(dāng)?shù)纳舷挛膩韴?zhí)行Runnable對象莫绣。而ExecutorService對象是使用Executors的靜態(tài)方法得到Java中的線程池

//Executor接口實現(xiàn)

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

  • Java 的四種線程池

    -Java中為我們提供了四種線程池畴蒲,他們分別是FixedThreadPool、CachedThreadPool对室、ScheduledThreadPool模燥、SingleThreadExector

    • FixedThreadPool

      • 創(chuàng)建方式為使用Executors的newFixedThreadPool()方法來創(chuàng)建,這種線程池的線程數(shù)量是固定的掩宜,可以看到他的靜態(tài)方法需要傳入線程的數(shù)量蔫骂,在空閑狀態(tài)下不會被系統(tǒng)回收,除非它被關(guān)閉了牺汤。當(dāng)它的所有線程都在執(zhí)行任務(wù)的時候辽旋,新加入的線程就會出來等待狀態(tài),等到有線程空閑檐迟,新任務(wù)才會被執(zhí)行,如果新任務(wù)加入時線程池中有空閑的線程补胚,則意味著它可以快速響應(yīng)處理任務(wù)。
      • public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                     0L, TimeUnit.MILLISECONDS,
                                     new LinkedBlockingQueue<Runnable>());
        }
        
        
        /*
        * 獲取使用方法
        */
        Runnable r=new Runnable(){
        @Override
        run(){
         .....  
         }
        }
        
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(r)追迟;
        
    • CachedThreadPool

      • 創(chuàng)建方式為使用Executors的newCachedThreadPool()方法來創(chuàng)建溶其,由其靜態(tài)方法可以看出,他的線程數(shù)是Integer.MAX_VALUE敦间,可以說他的線程數(shù)是無限大瓶逃,也就是說只要有任務(wù),線程就會立即執(zhí)行每瞒,但是它的每一個線程在空閑狀態(tài)下是有超時機制的金闽,這個時間為60秒纯露,只要線程空閑時間超過60秒該線程就會被回收剿骨,如果所有的線程都處于由空閑狀態(tài)并且超過了60秒,則相當(dāng)于線程池中沒有任何埠褪,線程浓利,也就是說這時的線程池是不占用任何資源的,所以這個線程池比較適合執(zhí)行大量的耗時較少的任務(wù)

         public static ExecutorService newCachedThreadPool() {
         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                       60L, TimeUnit.SECONDS,
                                       new SynchronousQueue<Runnable>());
          }
      
          /*
          * 獲取使用方法
          */
          
          Runnable r=new Runnable(){
          @Override
            run(){
           .....  
            }
          }
          
          ExecutorService executor = Executors.newCachedThreadPool();
          executor.execute(r)钞速;
      
    • ScheduledThreadPool

      • 創(chuàng)建方式為使用Executors的newCachedThreadPool()方法來創(chuàng)建贷掖,這種線程池的核心線程數(shù)是固定的,而非核心線程數(shù)據(jù)是沒有限制的渴语,并且當(dāng)非核心線程空閑的的時候該線程就會被立即回收苹威,所以我們可以使用他來操作定時任務(wù)和重復(fù)的任務(wù)(和Task TimeTask 有些像)

      • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
        }
        
        public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
        }
        
        /*
         * 獲取使用方法
         */
        Runnable r=new Runnable(){
          @Override
           run(){
             .....  
            }
         }
        
         ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
         // 1000ms 后執(zhí)行任務(wù)
         executor.schedule(r,1000,TimeUnit.MICROSECONDS);
        
         // 延遲1000ms 每隔1000ms 重復(fù)執(zhí)行 任務(wù)
         executor.scheduleAtFixedRate(r,1000,1000,TimeUnit.MICROSECONDS)驾凶;
         
        
    • SingleThreadExector

      • 創(chuàng)建方式為使用Executors的newCachedThreadPool()方法來創(chuàng)建牙甫,這種線程只有唯一一個核心線程掷酗,并且保證所有執(zhí)行的的任務(wù)都在這一個線程中執(zhí)行,并且是順序執(zhí)行窟哺,也就不用在考慮線程同步的問題了泻轰。
      • public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
         }
         
          /*
           * 獲取使用方法
           */
         ExecutorService executor = Executors.newSingleThreadExecutor();
         executor.execute(r);
         
         
         Runnable r=new Runnable(){
          @Override
           run(){
          .....  
          }
         }
        
         ExecutorService executor = Executors.newSingleThreadExecutor();
         executor.execute(r)且轨;
        
        
  • 通過上面對Java四種線程池的介紹,我們可以發(fā)現(xiàn)最終都是新建ThreadPoolExecutor對象浮声,也就是說ThreadPoolExecutor才是線程池的核心實現(xiàn)。

    • ThreadPoolExecutor 比較常用的一個構(gòu)造方法

       public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
       }
      
      //參數(shù)含義
      corePoolSize:默認情況下核心線程數(shù)會一直存在旋奢,不管是否處于閑置狀態(tài)泳挥,
      但是如果線程池設(shè)置了核心線程數(shù),也就是ThreadPoolExecutor的allowCoreThreadTimeOut這個boolean
      為true黄绩,如果核心線程數(shù)為零羡洁,則allowCoreThreadTimeOut的值為true,超時時間為keepAliveTime的值,
      也就是CachedThreadPool線程池的所有線程都能夠回收的原因爽丹,他的核心線程數(shù)為零,也就是沒有核心線程
      
      maximumPoolSize:最大線程數(shù)
      
      keepAliveTime:非核心線程超時時長筑煮,如果allowCoreThreadTimeOut的值為true,
      則該超時時長也會作用于空閑狀態(tài)的核心線程
      
      unit:超時時長的時間單位 TimeUnit.MILLISECONDS/SECONDS/MINUTES(毫秒/秒/分鐘)
      
      workQueue:線程任務(wù)隊列粤蝎,存放線程任務(wù)
      
      threadFactory:線程池線程生產(chǎn)工廠真仲,為線程池創(chuàng)建新線程
      
      //我們看到構(gòu)造放中還有一個defaultHandler參數(shù),他其實是RejectedExecutionHandler對象
      defaultHandler:當(dāng)線程隊列滿了初澎,或者線程任務(wù)無法執(zhí)行則用該參數(shù)拋出通知RejectedExecutionException秸应,這里構(gòu)造方法暫時沒用到
      
    • 在Android中我們可以寫自己的線程管理類接,下面就來實現(xiàn)一個自己的線程池管理類來管理我們的線程

      /**
       * Created by 毛麒添 on 2018/8/1 0010.
       * 線程管理類碑宴,線程池為單例
       */
      
      public class ThreadManager {
      
      private static ThreadPool mThreadPool;
      
      public static ThreadPool getmThreadPool(){
        if (mThreadPool==null){
            synchronized (ThreadManager.class){
                if(mThreadPool==null){
                    //線程安全
                    mThreadPool=new ThreadPool(5,10,1L);
                }
            }
          }
         return mThreadPool;
      }
      
      
      //線程池
      public static class ThreadPool{
      
        private int corePoolSize;//核心線程數(shù) 5
        private int maximumPoolSize;//最大線程數(shù) 10
        private long keepAliveTime;//線程休眠時間 1秒
      
        private ThreadPoolExecutor executor;
      
        private ThreadPool(  int corePoolSize, int maximumPoolSize,long keepAliveTime){
              this.corePoolSize=corePoolSize;
              this.maximumPoolSize=maximumPoolSize;
              this.keepAliveTime=keepAliveTime;
        }
      
      
        public void execute(Runnable runnable){
            /**
             * int corePoolSize, 核心線程數(shù)
             * int maximumPoolSize, 最大線程數(shù)
             * long keepAliveTime, 線程休眠時間
             * TimeUnit unit, 時間單位
             * BlockingQueue<Runnable> workQueue, 線程隊列
             * ThreadFactory threadFactory, 生成線程的工廠
             */
            if(executor==null){
                executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,
                        TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(),
                        Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
            }
            //核心線程也有超時機制
            executor.allowCoreThreadTimeOut(true);
            executor.execute(runnable);
        }
        //取消任務(wù)软啼,從任務(wù)隊列中將其移除
        public void cancelTask(Runnable runnable){
            if(runnable!=null){
                executor.getQueue().remove(runnable);
             }
      
           }
        }
      
      }
      
      
      //使用
      ThreadManager.getmThreadPool().execute(new Runnable() {
                @Override
                public void run() {
                    //執(zhí)行任務(wù)
                }
            });
      
      

好了,這就是我所了解的線程池知識延柠,如果有錯祸挪,請給我留言指出,大家一起學(xué)習(xí)進步贞间。

  • 參考資料:

    • 《Android開發(fā)藝術(shù)探索》
    • 《Java編程思想》(第四版)
      同步掘金地址
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贿条,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子增热,更是在濱河造成了極大的恐慌整以,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峻仇,死亡現(xiàn)場離奇詭異公黑,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門凡蚜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奠骄,“玉大人,你說我怎么就攤上這事番刊『郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵芹务,是天一觀的道長蝉绷。 經(jīng)常有香客問我,道長枣抱,這世上最難降的妖魔是什么熔吗? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮佳晶,結(jié)果婚禮上桅狠,老公的妹妹穿的比我還像新娘。我一直安慰自己轿秧,他們只是感情好中跌,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菇篡,像睡著了一般漩符。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驱还,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天嗜暴,我揣著相機與錄音,去河邊找鬼议蟆。 笑死闷沥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咐容。 我是一名探鬼主播舆逃,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疟丙!你這毒婦竟也來了颖侄?” 一聲冷哼從身側(cè)響起鸟雏,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤享郊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后孝鹊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炊琉,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了苔咪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锰悼。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖团赏,靈堂內(nèi)的尸體忽然破棺而出箕般,到底是詐尸還是另有隱情,我是刑警寧澤舔清,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布丝里,位于F島的核電站凳谦,受9級特大地震影響啸蜜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缸沃,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一抒痒、第九天 我趴在偏房一處隱蔽的房頂上張望幌绍。 院中可真熱鬧,春花似錦故响、人聲如沸傀广。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽主儡。三九已至,卻和暖如春惨缆,著一層夾襖步出監(jiān)牢的瞬間糜值,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工坯墨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寂汇,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓捣染,卻偏偏與公主長得像骄瓣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耍攘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一.Java中的ThreadPoolExecutor類 java.uitl.concurrent.ThreadPo...
    誰在烽煙彼岸閱讀 645評論 0 0
  • Label是比較常用的一個控件,記錄一些比較使用的技術(shù) 一榕栏、計算Label的高度 計算單行指定字體大小下的高度 具...
    Onegeng閱讀 1,516評論 0 2
  • 女兒:這幾天連續(xù)下雨,女兒早上又在說咋去蕾各,我提出讓她自己走路去學(xué)校扒磁,她不同意:要求我陪她走路。式曲。妨托。1.是一個想要與...
    7556497b805f閱讀 191評論 0 0