Thinking in Java中併發這一章節的筆記摘要,溫習Java多線程編程。
併發編程使我們可以將程序劃分爲多個分離的任務。Java中使用多線程機制,一個線程就是在進程中的一個單一的順序控制流,其底層機制是切分CPU時間。
定義任務
線程驅動任務,Java中用Runnable接口來提供描述任務的方式——實現Runnable接口並重寫run()方法。
Thread.yield()的調用是對線程調度器的建議,建議可以將CPU轉移給其他具有相同優先級的線程,但這完全是選擇性的。
我們可以在main()中直接調用該任務,即new一個任務對象並執行run()方法,這樣任務就附在了分配給main()的那個線程。
要實現線程行爲,必須顯示地將一個任務附着到線程上。
Thread類
將Runnable對象附着到線程上的一般方法是把它交給Thread構造器。
即Thread t=new Thread(new Runnable());
t.start();
當同時運行多個線程時,兩次結果可能不同,因爲線程調度機制是非確定的。
Executor
Java SE5的java.util.concurrent包中的Executor可以管理Thread對象,而無需顯式地管理線程的生命週期,從而簡化併發編程。
ExecutorService exec=Executors.newCachedThreadPool();
exec.execute(new Runnable());
exec.shutdown();
其中CachedThreadPool()在程序執行過程中通常會創建與所需數量相同的線程,然後再它回收舊線程時停止創建新線程,因此它是合理的Executor的首選。
FixedThreadPool()用於創建線程數爲固定數量的情況。
從任務中產生返回值
如果希望當任務完成時能夠返回一個值,那麼可以實現Callable接口而不是Runnable接口。在Java SE5中引入的Callable是一種具有類型參數的泛型,它的類型參數表示的是從方法call()中返回的值,並且必須使用ExecutorService.submit()方法調用它。
如在TaskWithResult implements Callable<String>中call方法定義返回的是String對象
在主線程中執行Future<String> fs=exec.submit(new TaskWithResult() and do sth.);
再用fs.get()得到Task的結果。
休眠
影響任務行爲的一種簡單方法時調用sleep(),這將使任務中止執行給定的時間。但是如果要控制任務執行的順序,最好的方法時使用同步控制,而不是sleep(),因爲它依賴於底層的線程機制,這種機制在不同的操作系統之間是有差異的。
優先級
優先級是在run()的開頭部分用Thread.currentThread().setPiority(priority);設定的。
加入一個線程
一個線程可以在其他線程之上調用join()方法,其效果是等待一段時間直到第二個線程結束才繼續執行。如果某個線程在另一個線程t上調用t.join(),此線程將被掛起,直到目標線程t結束才恢復。