標籤: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線程池