如果一個資源或對象可能被多個線程同時訪問,它就是一個共享資源;例如類的成員變量,包括類變量和實例變量,再比如對一個文件進行寫操作等。一般情況下,對共享資源的訪問需要考慮線程安全的問題。
如果一個對象的完整生命週期只在一個線程內,則不需要考慮線程安全,例如一個局部變量。下面爲一個示例代碼:
public class C1 {
public static java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
//其他代碼
}
假如在一個JSP中這樣的去調用:
<a.jsp>:
<%
Java.util.Date date = C1.sdf.parse(“2003-4-15”);
%>
則這樣的代碼不是線程安全的。因爲java.text.SimpleDateFormat不是線程安全的,a.jsp中的代碼將會有若干個線程同時執行,而都訪問的是同一個線程不安全的對象,這樣就不是一個線程安全的代碼。正確的寫法應該如下:
<a.jsp>:
<%
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
Java.util.Date date = sdf.parse(“2003-4-15”);
%>
2、 原因分析:
此時,sdf對象從創建到銷燬都位於一個方法中,相當於一個局部變量,不是一個共享資源,因此則沒有線程不安全的問題。
3、 解決方法或過程:
1) 如果對象是immutable,則是線程安全的,例如:String,可以放心使用。
2) 如果對象是線程安全的,則放心使用
3) 有條件線程安全,對於Vector和Hashtable一般情況下是線程安全的,但是對於某些特殊情況,需要通過額外的synchronized保證線程安全。
4) 使用synchronized關鍵字;
對於上例中可以改寫jsp代碼,在sdf上進行同步,而不需要每次創建一個新的對象來保證線程安全,代碼如下:
<%
synchronized(C1.sdf){
Java.util.Date date = C1.sdf.parse(“2003-4-15”);
}
%>
這種寫法是在一個對象級別上進行同步,也就是說任何時候,對於這個對象,最多只能有一個線程在執行同步方法。
另外一種寫法是在Class級別上進行同步,寫法如下:
public class C1 {
public static java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
public void method(){
synchronized(C1.class){
//synchronized code
}
}
}
這種寫法表示無論C1有多少個實例,在任何一個時間點,最多只能有一個線程和一個實例進入同步塊中。這種同步會比較大的影響性能。
5) 有些對象不能在多線程間共享,則只能在方法內部使用,或者只在一個線程內部使用。