同步最基本的目的是保证原子性。另一个容易忽略的目的是可见性,即一个线程修改的共享数据对另一个线程可见。
因为一些基本类型的赋值操作本身是原子的。所以针对这些赋值操作在不使用synchronized的情况下,可以使用volatile来解决一个线程的修改对另一个线程的可见。 所以volatile是在能保证原子性的前提下,避免使用synchronized解决可见性的办法。
private static volatile int nextSerialNumber = 0;
public static int generateSerialNumber() {
//由于nextSerialNumber++这样的“赋值”其实分解成多个步骤。这样下面的方法就不能保证原子性了。
return nextSerialNumber++;
}
改进:
private static int nextSerialNumber = 0;
//如果使用synchronized,volatile就可以省略了。后者一样可以保证可见性。
synchronized public static int generateSerialNumber() {
return nextSerialNumber++;
}
或者:
//AtomicLong是CAM机制保证可见性与原子性。
private static final AtomicLong nextSerialNum = new AtomicLong();
public static long generateSerialNumber() {
return nextSerialNum.getAndIncrement();
}