接上一篇文章,又來為大家在10分鐘內講解一些有關Thread-safety的介紹。
再講多3個做到Thread-safety的方式。
大家可以因應情況選擇一個最合適的表達方法。
7. Synchronized Methods
在同一時間只有一個thread能存取synchronized method,
而其他threads會被阻擋直到第一個thread/之前的thread完成所以任務或者出現例外(exception)。
下面會是一個thread-safe的例子
public synchronized void incrementCounter() {
counter += 1;
}
首先,在synchronized method的名字前必須有一個synchronized的關鍵字。有了synchronized method,
可以避免多個threads同時存取method。
synchronized method是依賴 內在鎖“intrinsic locks” 或監視鎖 “monitor locks”來完成它的功能。
intrinsic lock是一個與class中特定的實例有關的內在實體。
而在多個threads的環境中,monitor locks只是一個監視角色作為監測不包括的存取情況。
當一個thread使用synchronized method時,它就會獲得一個內在鎖(intrinsic locks)。
在完成了所有任務後,那個thread就會釋放內在鎖(intrinsic locks),允許其他threads來獲得這個內在鎖(intrinsic locks)以存取synchronized method。
大家可以實作同步化在instance methods, static methods 和 statements (synchronized statements)。
8. Synchronized Statements
有時候,當我們只是對於一個segment來進行thread-safe就會有機會出現問題。為了解決及預防,我們可以重新打造incrementCounter() method:
public void incrementCounter() {
// additional unsynced operations
synchronized(this) {
counter += 1;
}
}
在method內有不同operations,有些要用synchronization,有些是不同的。
針對一些需要用到synchronization的地方,我們可以將那個部分放到synchronized block內。
與synchronized methods不同,synchronized statements必須具體指出物件,
而在這條件下,可以透過使用this reference來滿足。
由於Synchronization的成本高,所以運用了這個方法可以只針對method中的某一部份來做synchronize。
9. Volatile Fields
在一般class中, Class變量的值會被儲存在CPU。
不過由於這個情況會對變量的可見性受到影響,有可能會出現不被其他threads見到的情況。
為了預防這個情況,我們可以使用volatile關鍵字來定義變量。
public class Counter {
private volatile int counter;
// standard constructors / getter
}
運用了volatile關鍵字,可以將變量的值直接儲存在主記憶體內。以上的例子就是把counter儲存在主記憶體內。所以當執行這個程序時,它會直接去主記憶體查找而不是在CPU的cache內。而每一次JVM在寫入counter的值時都會直接寫進主記憶體內。
而且運用了volatile關鍵字,可以讓其他thread都能夠在主記憶體內見到所有變量的值。
下面會是一個例子解釋:
public class User {
private String name;
private volatile int age;
// standard constructors / getters
}
每次JVM都會把變量age寫進主記憶體內,但同一時間也會將變量name寫進主記憶體內。因此,這也保證了所有變量的值都會儲存在主記憶體。也可以確保所有threads都能在主記憶體內見到它們的值。