標籤:blog http java 使用 strong 資料 for 2014
使用線程池最佳化多線程編程
認識線程池
在Java中,所有的對象都是需要通過new操作符來建立的,
如果建立大量短生命週期的對象,將會使得整個程式的效能非常的低下。
這種時候就需要用到了池的技術,比如資料庫連接池,線程池等。
在java1.5之後,java內建了線程池,在util包下新增了concurrent包,
這個包主要作用就是介紹java線程和線程池如何使用的。
在包java.util.concurrent下的 Executors類中定義了Executor、ExecutorService、ScheduledExecutorService、
ThreadFactoryScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。
此類支援以下各種方法:
a.建立並返回設定有常用配置字串的 ExecutorService 的方法。
b.建立並返回設定有常用配置字串的 ScheduledExecutorService 的方法。
c.建立並返回“封裝的”ExecutorService 方法,它通過使特定於實現的方法不可訪問來禁用重新設定。
d.建立並返回 ThreadFactory 的方法,它可將新建立的線程設定為已知的狀態。
e.建立並返回非閉包形式的 Callable 的方法,這樣可將其用於需要 Callable 的執行方法中。
--如果朋友您想轉載本文章請註明轉載地址"http://www.cnblogs.com/XHJT/p/3897773.html "謝謝--
首先我們先來比較一下用線程池建立多個線程和用獨立啟動並執行方式建立多個線程的區別,
這裡我們將通過比較兩種方法佔有記憶體和花費時間,來說明線程池的必要性和重要性。
代碼執行個體:
package com.xhj.thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * 比較獨立建立和線程池建立線程的優劣 比較因素--時間和佔用記憶體 * * @author XIEHEJUN * */public class CompareThreadPool implements Runnable { private int id = 0; @Override public void run() { id++; } public static void main(String[] args) { /** * 獨立建立1000個線程 */ { // 擷取當前程式運行時對象 Runtime run = Runtime.getRuntime(); // 調用記憶體回收機制,以減少記憶體誤差 run.gc(); // 擷取當前JVM的空閑記憶體 long freeMemory = run.freeMemory(); // 系統目前時間 long timePro = System.currentTimeMillis(); // 獨立建立並執行1000個線程 for (int i = 0; i < 1000; i++) { new Thread(new CompareThreadPool()).start(); } System.out.println("獨立建立並執行1000個線程所需要佔用的記憶體大小: " + (freeMemory - run.freeMemory())); System.out.println("獨立建立並運行1000個線程需要的時間為: " + (System.currentTimeMillis() - timePro)); } /** * 利用線程池建立1000個線程 */ { // 擷取當前程式運行時對象 Runtime run = Runtime.getRuntime(); // 調用記憶體回收機制,以減少記憶體誤差 run.gc(); // 擷取當前JVM的空閑記憶體 long freeMemory = run.freeMemory(); // 系統目前時間 long timePro = System.currentTimeMillis(); ExecutorService service = Executors.newFixedThreadPool(2); // 獨立建立並執行1000個線程 for (int i = 0; i < 1000; i++) { service.submit(new CompareThreadPool()); } System.out.println("使用線程池建立1000個線程所需要佔用的記憶體大小: " + (freeMemory - run.freeMemory())); // 線程池使用完成,關閉線程池 service.shutdown(); System.out.println("使用線程池建立並運行1000個線程需要的時間為: " + (System.currentTimeMillis() - timePro)); } }}
結果為:
結論--為什麼要用線程池:
通過上面這個例子,我們知道使用線程池可以大大的提高系統的效能,提高程式任務的執行效率,
節約了系統的記憶體空間。線上程池中,每一個背景工作執行緒都可以被重複利用,可執行多個任務,
減少了建立和銷毀線程的次數。能夠根據系統的承受能力,調整其線程數目,以便使系統達到啟動並執行最佳效果。
線程池原理:
一個線程池中有多個處於可運行狀態的線程,當向線程池中添加Runnable或Callable介面對象時,
就會有一個線程來執行run()方法或call()方法。如果方法執行完畢,則該線程並不終止,
而是繼續在池中處於可運行狀態,以運行新的任務。
瞭解線程池(java中建立線程池的幾種常用靜態方法)
在java中,線程池的頂級介面是util.concurrent包下的Executors工具類,在這個類裡,定義了很多操作線程池的方法。
其中最常用的線程池有:
1.建立單線程的線程池:
newSingleThreadExecutor(),建立一個只有一個線程的線程池,此單線程按照任務的提交順序執行所有的任務,
若遇到異常中斷,線程池則會重建立立一個單線程來替代其完成後續工作。
代碼執行個體:
/** * 建立一個單線程的線程池 * * @return */ public ExecutorService SingleThreadPool() { ExecutorService singlePool = Executors.newSingleThreadExecutor(); return singlePool; }
2.建立一個可快取的線程池:
newCachedThreadPool(),建立一個不限制大小,且只能的線程池,他會根據任務量的多少來開闢和減少記憶體空間,
但是線程池中線程的大小依賴於系統的效能或者JVM的容量
代碼執行個體:
/** * 建立一個可緩衝線程池 * * @return */ public ExecutorService CachedThreadPool() { ExecutorService cachedPool = Executors.newCachedThreadPool(); return cachedPool; }
3.建立一個大小固定的線程池:
newFixedThreadPool(),建立一個固定大小的線程池,任務提交則建立線程,直到線程大小達到線程池允許最大值,
若某個線程結束,線程池則補充一個新的線程。
代碼執行個體:
/** * 建立一個大小固定的線程池 * * @return */ public ExecutorService FixedThreadPool() { ExecutorService fixedPool = Executors.newFixedThreadPool(2); return fixedPool; }
4.建立一個可定時、周期性執行的線程池
newScheduledThreadPool(),建立一個可定時、周期性執行的線程池,此線程池沒有大小限制,
實現週期性任務調度。
代碼執行個體:
ScheduledThreadPoolExecutor scheduledPool = new ScheduledThreadPoolExecutor(1);
為了便於大家理解和對比其不同之處,下面將把這幾個常用線程池整合到一個程式當中,
代碼執行個體:
package com.xhj.thread;import java.util.Scanner;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;/** * 幾個常用線程池的理解與運用 * * @author XIEHEJUN * */public class CreateThreadPools extends Thread { @Override public void run() { System.out.println("系統時間 : " + System.currentTimeMillis() + " 線程: " + Thread.currentThread().getName() + "正在執行!!"); } /** * 建立一個單線程的線程池 * * @return */ public ExecutorService SingleThreadPool() { ExecutorService singlePool = Executors.newSingleThreadExecutor(); return singlePool; } /** * 建立一個大小固定的線程池 * * @return */ public ExecutorService FixedThreadPool() { ExecutorService fixedPool = Executors.newFixedThreadPool(3); return fixedPool; } /** * 建立一個可緩衝線程池 * * @return */ public ExecutorService CachedThreadPool() { ExecutorService cachedPool = Executors.newCachedThreadPool(); return cachedPool; } /** * 將建立好的線程放入線程池,並執行 * * @param pool */ public void service(ExecutorService pool) { // 建立線程 Thread thread1 = new CreateThreadPools(); Thread thread2 = new CreateThreadPools(); Thread thread3 = new CreateThreadPools(); Thread thread4 = new CreateThreadPools(); Thread thread5 = new CreateThreadPools(); // 線程入線程池,並執行 pool.execute(thread1); pool.execute(thread2); pool.execute(thread3); pool.execute(thread4); pool.execute(thread5); // 關閉線程池 pool.shutdown(); } /** * 建立一個大小無限制的線程池,可用與定時和周期性服務 */ public void scheduledThreadPool() { ScheduledThreadPoolExecutor scheduledPool = new ScheduledThreadPoolExecutor(1); scheduledPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("=======" + System.currentTimeMillis() + "========="); } }, 1000, 5000, TimeUnit.MILLISECONDS); scheduledPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(System.nanoTime()); } }, 1000, 2000, TimeUnit.MILLISECONDS); } public static void main(String[] args) { CreateThreadPools creatThreadPool = new CreateThreadPools(); Scanner sc = new Scanner(System.in); while (true) { System.out.println("請選擇建立線程池:1.單線程線程池;2.可緩衝線程池;3.固定大小線程池;4可定時周期性執行線程池"); int i = sc.nextInt(); switch (i) { case 1: System.out.println("-----調用單線程的線程池-----"); // 調用單線程的線程池 creatThreadPool.service(creatThreadPool.SingleThreadPool()); break; case 2: System.out.println("-----調用可緩衝線程的線程池-----"); // 調用可緩衝線程的線程池 creatThreadPool.service(creatThreadPool.CachedThreadPool()); break; case 3: System.out.println("-----調用固定大小線程的線程池-----"); // 調用固定大小線程的線程池 creatThreadPool.service(creatThreadPool.FixedThreadPool()); break; case 4: System.out.println("-----調用大小無限制可定時和周期性執行的線程池-----"); // 調用固定大小線程的線程池 creatThreadPool.scheduledThreadPool(); break; } } }}
註:當線程池任務結束之後,一定要記得將線程池關閉,執行shutdown()方法。