阅读时间: 10分钟
接上一篇文章,又来为大家在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都能在主记忆体内见到它们的值。