Java線程池

來源:互聯網
上載者:User

標籤:available   gui   結構   dex   body   jdk1.5   catch   final   活動   

new Thread的弊端:

1 new Thread(new Runnable() {2 3     @Override4     public void run() {5         // TODO Auto-generated method stub6     }7 }).start();

new Thread的弊端如下:

  a. 每次new Thread建立對象效能差。
  b. 線程缺乏統一管理,可能無限制建立線程,相互之間競爭,及可能佔用過多系統資源導致死機或oom。
  c. 缺乏更多功能,如定時執行、定期執行、線程中斷。
相比new Thread,Java提供的四種線程池的好處在於:
  a. 降低資源消耗。通過重複利用已建立的線程降低線程建立和銷毀造成的消耗。
  b. 提高響應速度。當任務到達時,任務可以不需要等到線程建立就能立即執行。
  c. 高線程的可管理性。線程是稀缺資源,如果無限制的建立,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。

 

可以通過ThreadPoolExecutor來建立一個線程池:

1     public ThreadPoolExecutor(int corePoolSize,2                               int maximumPoolSize,3                               long keepAliveTime,4                               TimeUnit unit,5                               BlockingQueue<Runnable> workQueue) {6         this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,7              Executors.defaultThreadFactory(), defaultHandler);8     }

 

  corePoolSize(線程池的基本大小):當提交一個任務到線程池時,線程池會建立一個線程來執行任務,即使其他閒置基本線程能夠執行新任務也會建立線程,等到需要執行的任務數大於線程池基本大小時就不再建立。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前建立並啟動所有基本線程。

  maximumPoolSize(線程池最大大小):線程池允許建立的最大線程數。如果隊列滿了,並且已建立的線程數小於最大線程數,則線程池會再建立新的線程執行任務。值得注意的是如果使用了無界的任務隊列這個參數就沒什麼效果。

  keepAliveTime(線程活動保持時間):線程池的背景工作執行緒空閑後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。

  TimeUnit(線程活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

   runnableTaskQueue(任務隊列):用於儲存等待執行的任務的阻塞隊列。

    ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。

    LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,輸送量通常要高於ArrayBlockingQueue。靜態Factory 方法Executors.newFixedThreadPool()使用了這個隊列。

    SynchronousQueue:一個不儲存元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,輸送量通常要高於LinkedBlockingQueue,靜態Factory 方法Executors.newCachedThreadPool使用了這個隊列。

    PriorityBlockingQueue:一個具有優先順序的無限阻塞隊列。

  ThreadFactory:用於設定建立線程的工廠,可以通過線程工廠給每個建立出來的線程設定更有意義的名字。

  RejectedExecutionHandler(飽和策略):當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicy,表示無法處理新任務時拋出異常。以下是JDK1.5提供的四種策略。

    AbortPolicy:直接拋出異常。

    CallerRunsPolicy:只用調用者所線上程來運行任務。

    DiscardOldestPolicy:丟棄隊列裡最近的一個任務,並執行當前任務。

    DiscardPolicy:不處理,丟棄掉。

    當然也可以根據應用情境需要來實現RejectedExecutionHandler介面自訂策略。如記錄日誌或持久化不能處理的任務。

 

Java通過Executors提供四種線程池,分別為:
  newFixedThreadPool 建立一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。

  newSingleThreadExecutor 建立一個單線程化的線程池,它只會用唯一的背景工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。

  newCachedThreadPool建立一個可緩衝線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則建立線程。

  newScheduledThreadPool 建立一個定長線程池,支援定時及週期性任務執行。

  他們的底層都是ThreadPoolExecutor。


newFixedThreadPool :

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

  corePoolSize和maximumPoolSize的大小是一樣的,因為如果使用無界queue的話maximumPoolSize參數是沒有意義的

  BlockingQueue選擇了LinkedBlockingQueue,該queue有一個特點,他是無界的。

 

 1 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); 2 for (int i = 0; i < 10; i++) { 3     final int index = i; 4     fixedThreadPool.execute(new Runnable() { 5  6         @Override 7         public void run() { 8             try { 9                 System.out.println(index);10                 Thread.sleep(2000);11             } catch (InterruptedException e) {12                 // TODO Auto-generated catch block13                 e.printStackTrace();14             }15         }16     });17 }

  因為線程池大小為3,每個任務輸出index後sleep 2秒,所以每兩秒列印3個數字。

  定長線程池的大小最好根據系統資源進行設定。如Runtime.getRuntime().availableProcessors()。

 

newSingleThreadExecutor:

1 public static ExecutorService newSingleThreadExecutor() {2         return new FinalizableDelegatedExecutorService3             (new ThreadPoolExecutor(1, 1,4                                     0L, TimeUnit.MILLISECONDS,5                                     new LinkedBlockingQueue<Runnable>()));6     }

  相當於newFixedThreadPool(1)

 

 1 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); 2 for (int i = 0; i < 10; i++) { 3     final int index = i; 4     singleThreadExecutor.execute(new Runnable() { 5  6         @Override 7         public void run() { 8             try { 9                 System.out.println(index);10                 Thread.sleep(2000);11             } catch (InterruptedException e) {12                 // TODO Auto-generated catch block13                 e.printStackTrace();14             }15         }16     });17 }

  結果依次輸出,相當於順序執行各個任務。

  現行大多數GUI程式都是單線程的。

 

newCachedThreadPool:

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

  首先是無界的線程池,所以我們可以發現maximumPoolSize為max。其次BlockingQueue的選擇上使用SynchronousQueue:每個插入操作必須等待另一個線程的對應移除操作。

  比如,我先添加一個元素,接下來如果繼續想嘗試添加則會阻塞,直到另一個線程取走一個元素,反之亦然。(就是緩衝區為1的生產者消費者模式)

 

 1 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 2 for (int i = 0; i < 10; i++) { 3     final int index = i; 4     try { 5         Thread.sleep(index * 1000); 6     } catch (InterruptedException e) { 7         e.printStackTrace(); 8     } 9 10     cachedThreadPool.execute(new Runnable() {11 12         @Override13         public void run() {14             System.out.println(index);15         }16     });17 }

  線程池為無限大,當執行第二個任務時第一個任務已經完成,會複用執行第一個任務的線程,而不用每次建立線程。

 

newScheduledThreadPool:

1     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {2         return new ScheduledThreadPoolExecutor(corePoolSize);3     }4 5     public ScheduledThreadPoolExecutor(int corePoolSize) {6         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,7               new DelayedWorkQueue());8     }

 

1 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);2 scheduledThreadPool.schedule(new Runnable() {3 4     @Override5     public void run() {6         System.out.println("delay 3 seconds");7     }8 }, 3, TimeUnit.SECONDS);

  表示延遲3秒執行。

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {    @Override    public void run() {        System.out.println("delay 1 seconds, and excute every 3 seconds");    }}, 1, 3, TimeUnit.SECONDS);

  表示延遲1秒後每3秒執行一次。

  ScheduledExecutorService比Timer更安全,功能更強大,

Java線程池

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.