1. synchronized function
用法: synchronized foo() {}
字面意思是讓一個函數塊保持同步,但是保持和誰同步呢? 答案是和另一個或一些加了synchronized 關鍵字的函數,它能保證在這個對象內,所有加synchronized 的函數在同一時間只有一個在運行,並只運行在某一個線程中,假如這些函數可能會被運行在不同的線程,又要同時訪問同一個資源,那麼就可以用它了。 (這段話不知道我說對了沒有)Only
one thread at a time can call a synchronized method for a particular object (although that thread can call more than one of the object’s synchronized methods). Objects
can have synchronized methods that prevent threads from accessing that object until the synchronization lock is released。
例如 :
synchronized foo0() { A;}
synchronized foo1() { B;}
A, B 之間如果想同步,(即A執行時B不能執行,B執行時A不能執行),需要把兩個函數都加上synchronized,只加一個相當於沒加。
If you synchronize only one of the methods, then the other is free to ignore the object lock and can
be called with impunity. This is an important point: Every method that accesses a critical shared resource must be synchronized or it won’t work
right.
2. synchronized object
用法:
synchronized(syncObject) { // This code can be accessed // by only one thread at a time}
字面意思是同步一個對象,實際上是用一個對象當作鎖,來建立一個臨界區(Critical section),臨界區內代碼同一時間只能由一個線程來訪問,進一步說,syncObject只有一把鑰匙,在一個時間點上,哪個線程拿到這把鑰匙,哪個線程就可以進入臨界區,執行完後返回鑰匙給syncObject,其它沒鑰匙的線程等鑰匙空閑了之後,再由系統決定把鑰匙給誰。
注意:synchronized 方法濫用會降低系統效能,因為進入、退出同步方法(塊)時會多一些操作,盡量少用。
另外, 在非同步線程中訪問另一個線程的ArrayList,應該複製一份:
ArrayList lv = null; // Make a shallow copy of the List in case // someone adds a listener while we're // calling listeners: synchronized(this) { lv = (ArrayList)actionListeners.clone(); }
其中,synchronized(this) {}相當於synchronized foo() {}的效果,即用當前對象的大鎖來同步。PS synchronized 不會被子類繼承。
線程基本知識:線程的四種狀態:1 新的2 可啟動並執行 Runnable 隨時可能被運行,有時運行,有時不運行3 死的 Dead 通常發生在run{}退出後4 阻塞的 Blocked
3 How to BLOCK a Thread? 多線程的重點是如何去阻塞一個線程?目的是利用阻塞來實現某種程度的同步。阻塞有兩種:Sleep和 wait/notify。區別:Sleep不釋放當前線程對象的鎖,而wait釋放當前線程的鎖,由notify來重新拿回鎖,拿回鎖之後,執行wait()之後的程式。使用wait/notify的注意事項:因為這兩個函數要操作當前對象的鎖,不能做“無米之炊”,操作鎖之前要拿到這把鎖,然而什麼時機才能確保我們手中有鎖呢?答案是在synchronized 同步塊(方法)中,其中同步塊即synchronized(Object o){},可以確保拿到Object的鎖, 而同步方法即 synchronized void foo() {}, 可以確保拿到些函數所處對象的鎖,總結以上的經驗, 應該這樣來調用wait()/notify():
synchronized (object) { ... try { object.wait(); } catch(InterruptedException e) { } //object.notify(); ...}synchronized void foo () { ... try { wait(); //Current thread wait(); } catch(InterruptedException e) { } //object.notify(); ...}
注意catch線程中斷的異常。
4 死結當一個線程A因為另一個線程B而阻塞,而線程B因為線程C阻塞,C又因為A阻塞,這樣的無限迴圈造成死結。寫程式的時候一定要小心,因為一旦出現死結,你將會“死”很久去調試。
5 退出線程的方法5.1 Use stop mark:
public void terminate() { stop = true; } public void run() { while (!stop) { ...... }}5.2 interrupt():
// blocked is a thread
if(blocked == null) return; Thread remove = blocked; blocked = null; // to release it remove.interrupt();
Note:開太多的線程可能會導致JVM停滯,能用線性地方就不用多線程,線性過程比多線程快!線程一般用於提高使用者響應速度,網路下載等。