前言 我们知道,在多线程环境下使用竞争资源,为了保证程序正确性,进入临界区之前需要加锁保护。Java中的volatile和synchonized两个关键字作为同步手段常常令人疑惑。什么时候该用volatile,什么时候该用synchonized,一直不太明确,今天就来捋捋吧。
区别 关于两者的区别,老外有篇文章列了个表,此处引用一下(出处:https://www.javamex.com/tutorials/synchronization_volatile.shtml):
volatile用法 用法1 在多线程环境下改变标志位,这也是volatile关键字最典型的用法。
1 2 3 4 5 6 7 8 9 10 11 12 public class StoppableTask extends Thread { private volatile boolean pleaseStop; public void run () { while (!pleaseStop) { } } public void tellMeToStop () { pleaseStop = true ; } }
用法2 在单例模式中使用。至于为何要加volatile关键字,可以看此处:https://www.javamex.com/tutorials/double_checked_locking_fixing.shtml#。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Singleton { private static volatile Singleton instance; private int field1, field2 ... private Singleton () {} public static Singleton getInstance () { if (instance == null ) { synchronized (Singleton.class) { if (instance == null ) { instance = new Singleton (); } } } return instance; } }
synchronized用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class Test { private Object count = new Object (); private final Object obj = new Object (); public synchronized void work1 () { } public synchronized static void work2 () { } public void work3 () { synchronized (this ) { } } public void work4 () { synchronized (Test.class) { } } public void work5 () { synchronized (obj) { } } public void work6 () { synchronized (count) { } } }
总结 下方是几种比较常见加锁的方案。自己使用锁(work1())可能会比synchronized快一丢丢,但是Java中synchronized关键字大部分情况下已满足需求,不到万不得已,没必要自己写锁保护。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Test { private byte [] obj = new byte [0 ]; private final Lock lock = new ReentrantLock (); public void work1 () { lock.lock(); try { } finally { lock.unlock(); } } public void work2 () { synchronized (obj) { } } public void work3 () { synchronized (this ) { } } public void work4 () { synchronized (Test.class) { } } }
参考文章