Java Concurrent包常用方法簡介
1 Executor接口
留給開發者自己實現的接口,一般情況下不需要再去實現。它只有一個方法
void execute(Runnable command)</div>
2 ExecutorService接口
它繼承自Executor接口,但多了如下3個功能
- 終止任務。體現在這幾個方法
- void shutdown()
- 線程池關閉,不接受新任務,即不能再執行submit(task),如果你硬要執行新任務則會拋異常。
- 還沒運行完的任務繼續運行完畢. </ol> </li>
- List<Runnable> shutdownNow()
- 試圖停止所有正在執行的活動任務,但不一定成功。
- 返回等待執行的任務列表。 </ol> </li> </ol> </li>
- 任務提交者與任務的通信,就是Future對象的使用。Future有點類似 windows開發中的句柄概念,通過它可對任務進行監控并獲取任務信息。有三種使用方式:
1. <T> Future<T> submit(Callable<T> task)
- Future<?> submit(Runnable task)
- <T> Future<T> submit(Runnable task, T result)</pre>
- 第一種方法提交的任務,當任務完成后,可以通過Future.get()獲取任務的返回值.
- 第三種方法提交的任務,當任務完成后,可以通過Future.get()獲取提交時傳遞的參數T result. 比如:
Future<String> future = service.submit(task,"aaaa"); String s = future.get();// s="aaaa";
- 有趣的是第二種方式,因為它的Future.get()得不到任何內容,它返回值是Null,那為什么不直接把ExecutorService的接口設計成如下這種形式呢
void submit(Runnable task)
這是因為Future除了get這種獲取任務信息外,還可以控制任務,體現在 Future的這個方法上
boolean cancel(boolean mayInterruptIfRunning)
這個方法的JavaDoc解釋的很清楚
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
注意:如果任務沒執行完,這3種方式的Future.get()都會阻塞。
- 終止任務后可以阻塞一會兒。由ExecutorService的下面這個方法完成
boolean awaitTermination(long timeout,TimeUnit unit)
比如
service.shutdown(); service.awaitTermination(20, TimeUnit.SECONDS);
它的意思是,當service.shutdown()后,主線程阻塞,任務執行結束或者阻塞20秒以后,阻塞解除。
</ol>
</div>
</div>
- Timer沒有返對象(我總理解為一種句柄),不方便細粒度控制任務。
- Timer的任務類型比較單一,只有TimerTask一種。
- 沒有類似scheduleWithFixedDelay的方法。
- 間隔時間的表示方法也不友好。
- 性能上也不如ScheduledExecutorService(通過線程池等方式進行了性能優化)出色。
- 3類不同的ExecutorService實例.
static ExecutorService newSingleThreadExecutor()
啟動一個線程負責任務順序執行,順序意味著先提交的任務先執行。其原理是:任務會被提交到一個隊列里,啟動的那個線程會從隊里里取任務,然后執行,執行完,再從隊列里取下一個任務,再執行。如果該線程執行一個任務失敗,并導致線程結束,系統會創建一個新的線程去執行隊里里后續的任務,不會因為前面的任務有異常導致后面無辜的任務無法執行。
static ExecutorService newCachedThreadPool()
啟動N個線程處理N個任務。既然是多個線程運行,意味著任務不會順序運行。一個任務完成后,該線程空閑60秒會被結束。新提交的任務會發現空閑線程,并使用它,如果沒有空閑線程可用則創建新線程。其實,這就是一個動態線程池。適合于規模比較小、創建較頻繁的任務。
static ExecutorService newFixedThreadPool(int nThreads)
動態線程池不限制線程的數量,在有些情況下我們不希望線程數量不可控,則可以使用擁有固定線程數目的線程池。運作原理是:任務被提交到一個隊列里排隊,線程池里的空閑線程會把隊列里的任務提出來執行,每個線程執行完一個任務后,就去隊列里抓另一個任務出來執行。如果一個線程由于失敗而終止,系統會創建另一個線程執行后續任務。
- 帶ThreadFactory參數生成的ExecutorService實例。以上3種實例創建工作線程時都是用的默認的線程工廠類來創建。也可以指定自己的線程工廠類來創建,以newSingleThreadExecutor(ThreadFactory threadFactory)為例:
//你自己的實現 class YourselfThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) {
} }</pre></li>Thread thread = new Thread(r); doXXX; return thread;
- newSingleThreadExecutor 與 newFixedThreadPool(1) 區別.
JavaDoc上說:Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.
什么意思?不懂。為什么?不具體。具體一下就懂了。
((ThreadPoolExecutor)newFixedThreadPool(1)).setCorePoolSize(3);
即newFixedThreadPool(1)可以后期修改線程數,不能保證線程只有一個。而newSingleThreadExecutor可以保證。
- static Callable<Object> callable(Runnable task)
把Runnable任務轉換成Callable任務.例子如下
public static void test() throws Exception { Runnable task = new Runnable() {
Callable c = Executors.callable(task); ExecutorService service = Executors.newCachedThreadPool(); Future f = service.submit(c); System.out.println(f.get());//返回null log("end"); }public void run() { log("begin task"); try { Thread.sleep(1000); } catch (InterruptedException e) { } log("end task"); } };
3 ScheduledExecutorService接口
它繼承自ExecutorService接口。顧名思義,它主要用來定期執行任務或周期執行任務。它只有4個方法,都比較好理解。下面用最簡單的例子來做個說明
scheduler.schedule(callable,10,SECONDS); //10秒后開始執行callable任務 scheduler.schedule(runnable,10,Seconds); //10秒后開始執行runnable任務 scheduler.scheduleAtFixedRate(runnable, 5, 10, SECONDS); //5秒后開始執行Runnable任務,然后每隔10秒執行一遍該任務. scheduler.scheduleWithFixedDelay(runnable,5,10,SECONDS); //5秒后開始執行Runnable任務,然后任務執行完后再等10秒就執行一遍任務,即,每隔任務執行的時間+10秒再執行一遍任務。
這4個方法都返回ScheduledFuture對象.它繼承自Future接口,用途和Future差不多。
在JDK之前,計劃任務一般由java.until.Timer類來完成。但相比起 ScheduleExecutorService來說,Timer類的功能較為簡單,比如下例
private final static long fONCE_PER_DAY = 1000*60*60*24; Timer timer = new Timer(); timer.scheduleAtFixedRate(fetchMail, getTomorrowMorning4am(), fONCE_PER_DAY);
4 Executors類
這個類是一個工廠類,用來生成不同特點的ExecutorService或 ScheduledExecutorService實例。這里主要介紹這些不同特點的實例不同在什么地方。
private static void log(String message) { System.out.println(new Date() + ": " + message); }
public static void main(String args[]) throws Exception { test(); }</pre></li> </ol> </div> </div>
5 結束
JDK1.5引入的concurrent包使多線程編寫更加容易、代碼更容易理解、可讀性更好.本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!相關經驗
相關資訊
- void shutdown()