java是支持多線程編程的語言,java中提供了很多類,如果把這些類的實現按照線程安全級別來排序的話,則由強到弱主要可以分為以下幾個級別
1 絕對線程安全
在任何環境下,調用者都不需要考慮額外的同步措施,都能夠保證程序的正確性。
這個定義要求很嚴格,java里面滿足這個要求的類比較少,對於實現jsr133規范(java內存模型)的jdk(一般指jdk5.0之上),一般的不變類都是滿足絕地線程安全的。比如 String,Integer類。一般情況下,定義了如果一個類里面所有字段都是final類型的,一般都認為這個類是不變的。不變類都是絕對線程安全的。
但是下面這個類的定義,就不是絕對安全的。雖然沒有辦法修改Money類的屬性值(反射機制例外),但是在構造構造Money的時候,可能發生並發問題.這個可以參考Java內存模型-jsr133規范介紹里面的例子。
public class Money { private int yuan; private int fen; public Money(int yuan, int fen) { this.yuan = yuan; this.fen = fen; } public String formatString() { return "" + yuan + "." + fen; } }
2 相對線程安全
在一般情況下,調用者都不需要考慮線程同步,大多數情況下,都能夠正常運行。jdk里面大多數類都是相對安全的。最常見的例子是java里面Vector類。記得網上經典的面試問題就是Vertor 和 List的區別,一般情況下都會說Vertor是線程安全的,List是非線程安全的。但是考慮以下情況,一個線程遍歷Vector,另外一個線程刪除Vector中的一個元素,會導致什么問題?有可能在read方法中拋出ArrayIndexOutOfBoundException
import java.util.Vector; public class VectorTest { private static Vector v = new Vector(); public static void read() { int size = v.size(); for (int i = 0; i < size; i++) { v.get(i); } } public static void delete() { if (v.iterator().hasNext()) { v.remove(0); } } }
3 非線程安全
在多線程環境下,調用者需要考慮同步問題。如果調用者通過額外的同步機制,可以保證線程的安全性。
jdk中,List,Map,DateFormat等對象都是非線程安全的。所以在使用這些對象的時候,都要考慮是否會發生線程安全問題。
4 線程對立
在多線程環境中,無論采用什么樣的機制,都無法解決線程安全問題。這種還是極為少見的。比如java.lang.Thread類,提供了suspend,stop,resume方法。
suspend 和 resume 方法可能導致兩個線程死鎖。
例如 線程A,先鎖住關鍵資源S,然后被線程B suspend,由於資源被A鎖住,除非線程A被resume,否則其他線程無法訪問S,如果遇到S,則阻塞。 而線程B suspend線程A之后,需要申請關鍵資源S,獲取到S之后,在resume A。此時線程A 和 線程B就由可能導致死鎖。
對於stop方法,由於調用stop方法的時候,被stop的線程回釋放所有他獲得的所有monitor,被monitor保護的資源可能存在一致性問題。其他線程可能看到的對象就可能不一致。