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

在Java開發中,多線程執行任務是很常見的,Java也提供了線程類Thread來讓我們方便創建一個線程如下代碼所示

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

                }
            }.start();

  • 這樣創建新的線程有幾個缺點

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

Java SE5d的java.util.concurrent包 提供了Executor(執行器)來管理線程對象。Executor是一個接口,而ExecutorService繼承了Excutor接口,ExecutorService是一個具有生命周期的Executor,它知道如何構建恰當的上下文來執行Runnable對象。而ExecutorService對象是使用Executors的靜態方法得到Java中的線程池

//Executor接口實現

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

      • 創建方式為使用Executors的newFixedThreadPool()方法來創建,這種線程池的線程數量是固定的,可以看到他的靜態方法需要傳入線程的數量,在空閑狀態下不會被系統回收,除非它被關閉了。當它的所有線程都在執行任務的時候,新加入的線程就會出來等待狀態,等到有線程空閑,新任務才會被執行,如果新任務加入時線程池中有空閑的線程,則意味著它可以快速響應處理任務。
      • 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

      • 創建方式為使用Executors的newCachedThreadPool()方法來創建,由其靜態方法可以看出,他的線程數是Integer.MAX_VALUE,可以說他的線程數是無限大,也就是說只要有任務,線程就會立即執行,但是它的每一個線程在空閑狀態下是有超時機制的,這個時間為60秒,只要線程空閑時間超過60秒該線程就會被回收,如果所有的線程都處于由空閑狀態并且超過了60秒,則相當于線程池中沒有任何,線程,也就是說這時的線程池是不占用任何資源的,所以這個線程池比較適合執行大量的耗時較少的任務

         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

      • 創建方式為使用Executors的newCachedThreadPool()方法來創建,這種線程池的核心線程數是固定的,而非核心線程數據是沒有限制的,并且當非核心線程空閑的的時候該線程就會被立即回收,所以我們可以使用他來操作定時任務和重復的任務(和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 后執行任務
         executor.schedule(r,1000,TimeUnit.MICROSECONDS);
        
         // 延遲1000ms 每隔1000ms 重復執行 任務
         executor.scheduleAtFixedRate(r,1000,1000,TimeUnit.MICROSECONDS);
         
        
    • SingleThreadExector

      • 創建方式為使用Executors的newCachedThreadPool()方法來創建,這種線程只有唯一一個核心線程,并且保證所有執行的的任務都在這一個線程中執行,并且是順序執行,也就不用在考慮線程同步的問題了。
      • 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四種線程池的介紹,我們可以發現最終都是新建ThreadPoolExecutor對象,也就是說ThreadPoolExecutor才是線程池的核心實現。

    • ThreadPoolExecutor 比較常用的一個構造方法

       public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
       }
      
      //參數含義
      corePoolSize:默認情況下核心線程數會一直存在,不管是否處于閑置狀態,
      但是如果線程池設置了核心線程數,也就是ThreadPoolExecutor的allowCoreThreadTimeOut這個boolean
      為true,如果核心線程數為零,則allowCoreThreadTimeOut的值為true,超時時間為keepAliveTime的值,
      也就是CachedThreadPool線程池的所有線程都能夠回收的原因,他的核心線程數為零,也就是沒有核心線程
      
      maximumPoolSize:最大線程數
      
      keepAliveTime:非核心線程超時時長,如果allowCoreThreadTimeOut的值為true,
      則該超時時長也會作用于空閑狀態的核心線程
      
      unit:超時時長的時間單位 TimeUnit.MILLISECONDS/SECONDS/MINUTES(毫秒/秒/分鐘)
      
      workQueue:線程任務隊列,存放線程任務
      
      threadFactory:線程池線程生產工廠,為線程池創建新線程
      
      //我們看到構造放中還有一個defaultHandler參數,他其實是RejectedExecutionHandler對象
      defaultHandler:當線程隊列滿了,或者線程任務無法執行則用該參數拋出通知RejectedExecutionException,這里構造方法暫時沒用到
      
    • 在Android中我們可以寫自己的線程管理類接,下面就來實現一個自己的線程池管理類來管理我們的線程

      /**
       * 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;//核心線程數 5
        private int maximumPoolSize;//最大線程數 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, 核心線程數
             * int maximumPoolSize, 最大線程數
             * 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);
        }
        //取消任務,從任務隊列中將其移除
        public void cancelTask(Runnable runnable){
            if(runnable!=null){
                executor.getQueue().remove(runnable);
             }
      
           }
        }
      
      }
      
      
      //使用
      ThreadManager.getmThreadPool().execute(new Runnable() {
                @Override
                public void run() {
                    //執行任務
                }
            });
      
      

好了,這就是我所了解的線程池知識,如果有錯,請給我留言指出,大家一起學習進步。

  • 參考資料:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,238評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,430評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,134評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,893評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,653評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,136評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,212評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,372評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,888評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,738評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,482評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,179評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,588評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,829評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,610評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,916評論 2 372

推薦閱讀更多精彩內容

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