標籤:
實現一個線程需要實現Runnable介面,或繼承Thread類並實現run()方法。在run()方法中定義你需要線程完成的任務。
public class LiftOff implements Runnable { protected int countDown = 10; private static int taskCount = 0; private final int id = taskCount++; public LiftOff(){ } public LiftOff(int count){ this.countDown = count; } public String state(){ return "#"+id+"("+(countDown>0?countDown:"LiftOff")+")."; } @Override public void run() { // TODO Auto-generated method stub while(countDown-- > 0){ System.out.print(state()); Thread.yield(); } System.out.println("liftoff already!!"); }}
線程的一些操作和特徵:
- 從線程中傳回值,可以實現Callable介面,並重寫call方法。
- 線程休眠TimeUnit.MILLISECONDS.sleep(),TimeUnit是一個枚舉類
- 線程可以設定優先權
- 線程讓步yield()
- 後台線程daemon,非後台線程結束時,後台線程將被殺死
線程池介面
為了簡化多線程編程java SE5提供了執行器類來為我們管理Thread對象,執行器類在最底層定義了一個Executor介面,並聲明了一個execute方法。
ExecutorService
是真正意義上的線程池介面,其聲明了一些線程池的基本方法,submit方法向線程池中提交一個任務並返回一個Future對象;shutdown方法在執行完先前提交的任務後,不再接受新任務;shutdownNow方法 試圖停止所有正在執行的任務,停止等待執行的任務,並返回等待執行工作清單。ExecutorService還有聲明了批量執行任務的方法,就不詳細介紹了。
ThreadPoolExecutor
是真正的線程池實現。其實現了Executor的execute方法,execute方法與submit方法的區別在於execute是沒有傳回值的。作為線程池,應當提供的功能有設定線程池的線程數量,提供存放等待執行線程的容器,以及對過剩的任務的處理方式,下面來看看ThreadPoolExecutor的建構函式。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize線程池中維持的線程數量,即使有線程是閒置。
maximumPoolSize線程池中最大的線程數
keepAliveTime超出corePoolSize的線程,在結束之前維持等待新任務的空閑狀態時間
unit時間單元SECONDS、MILLISECONDS、MICROSECONDS…
workQueue用於儲存等待執行的任務,需要注意的是該隊列僅保持有execute提交的任務
threadFactory executor建立新線程使用的工廠
handler用來處理超出線程池容量的任務
- 向線程池中提交一個任務,當線程池中的線程數量少於corePoolSize時,會立即建立一個新的線程來處理該任務,而不管線程池中是否存在空閑線程;線程數量大於corePoolSize而少於maximumPoolSize時,會查看workQueue的情況,只有workQueue已滿時,才會建立新線程來處該任務。
- 可以使用prestartCoreThread或prestartAllCoreThreads()來建立空閑線程等待任務執行。
- 線程由ThreadFactory 建立,預設有Executors的ThreadFactory ,建立具有相同的線程組、優先順序、和非背景線程。
- 任務隊列workQueue有三種類型,直接提交(Direct handoffs)、無界隊列(Unbounded queues)、有界隊列(Bounded queues)。
- 直接提交,工作隊列的預設選項是 SynchronousQueue,它將任務直接提交給線程而不保持它們。在此,如果不存在可用於立即運行任務的線程,則試圖把任務排入佇列將失敗,因此會構造一個新的線程。此策略可以避免在處理可能具有內部依賴性的請求集時出現鎖。直接提交通常要求無界maximumPoolSizes 以避免拒絕新提交的任務。當命令以超過隊列所能處理的平均數連續到達時,此策略允許無界線程具有增長的可能性。簡單的講,這種方式
- 無界隊列,使用無界隊列(例如,不具有預定義容量的 LinkedBlockingQueue)將導致在所有 corePoolSize 線程都忙時新任務在隊列中等待。這樣,建立的線程就不會超過 corePoolSize。(因此,maximumPoolSize的值也就無效了)當每個任務完全獨立於其他任務,即任務執行互不影響時,適合於使用無界隊列;例如,在 Web頁伺服器中。這種排隊可用於處理瞬態突發請求,當命令以超過隊列所能處理的平均數連續到達時,此策略允許無界線程具有增長的可能性。
- 有界隊列,當使用有限的 maximumPoolSizes時,有界隊列(如 ArrayBlockingQueue)有助於防止資源耗盡,但是可能較難調整和控制。隊列大小和最大池大小可能需要相互折衷:使用大型隊列和小型池可以最大限度地降低 CPU 使用率、作業系統資源和環境切換開銷,但是可能導致人工降低輸送量。如果任務頻繁阻塞(例如,如果它們是 I/O邊界),則系統可能為超過您許可的更多線程安排時間。使用小型隊列通常要求較大的池大小,CPU使用率較高,但是可能遇到不可接受的調度開銷,這樣也會降低輸送量。
- 任務拒絕RejectedExecutionHandler用來處理Executor關閉、有限隊列及有限的maximumPoolSize的容量超出問題。ThreadPoolExecutor定義了四種類型的RejectedExecutionHandler
- ThreadPoolExecutor.AbortPolicy拋出運行時RejectedExecutionException異常
- ThreadPoolExecutor.CallerRunsPolicy線程調用運行該任務的 execute 本身。此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度。
- ThreadPoolExecutor.DiscardPolicy不能執行的任務將被拋棄
- ThreadPoolExecutor.DiscardOldestPolicy如果執行程式尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程式(如果再次失敗,則重複此過程)
- Hook函數,這個類提供了beforeExecute(Thread, Runnable),afterExecute(Runnable, Throwable)介面,在執行一個任務的前後調用。
ScheduledExecutorService
是一個ExecutorService,它提供了在給定一個延時或周期性調度任務的功能。
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
前兩個函數在等待延時delay後執行任務;scheduleAtFixedRate在等待時間delay後,並以period重複執行任務;scheduleWithFixedDelay在等待初始延時initialDelay後,並每次執行任務後等待delay重複執行任務。
Executors
Executors主要是提供了一些Factory 方法,用來產生常用的線程池:
- public static ExecutorService newCachedThreadPool(),採用SynchronousQueue來儲存等待啟動並執行任務,maximumPoolSize為Integer的最大值。
- public static ExecutorService newFixedThreadPool(),指定大小的線程池corePoolSize 和maximumPoolSize的大小相同,使用無界隊列LinkedBlockingQueue。
- public static ExecutorService newSingleThreadExecutor(),大小為1的FixedThreadPool,使用無界隊列LinkedBlockingQueue
- public static ScheduledExecutorService newScheduledThreadPool,建立可以指定延時執行或指定執行循環的線程池
public static void cachedPool() { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 5; ++i) { exec.submit(new LiftOff()); } exec.shutdown();}public static void fixedPool() { ExecutorService exec = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; ++i) { exec.submit(new LiftOff()); } exec.shutdown();}public static void singleThread() { ExecutorService exec = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; ++i) { exec.submit(new LiftOff()); } exec.shutdown();}public static void scheduledThread() { ScheduledThreadPoolExecutor exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(2); exec.scheduleAtFixedRate(new LiftOff(), 3, 12, TimeUnit.SECONDS); exec.scheduleAtFixedRate(new LiftOff(), 3, 6, TimeUnit.SECONDS);}
參考資料:http://blog.csdn.net/sd0902/article/details/8395677, JDK 1.7 API
Java多線程 線程池