首页 » 并发和多线程 » 正文

仅仅使用volatile修饰成员变量到底线程安全吗?

今天几个朋友在群里讨论下面的代码到底线程安全不安全?

code

我看了一下,我说这个程序是否线程安全应该分为两个方面来分析,

第一,这是一个单例模式,单例模式的实例在成员变量初始化的时候创建,变量初始化是在单线程下运行的,避免了任何的线程安全问题,在实例使用的时候直接返回给客户程序即可,不需要使用synchronized来修饰,即不需要互斥保护。

第二 ,这段程序还有个内存可见性的问题,由于isActive变量是个标志,这个标志可能由多个线程进行读取,因此本身是有线程安全问题的,一般我们写程序都会用sychronized关键字来保护,由于synchronized关键字即有互斥性又有线程可见性,因此是万无一失的,但是由于这里仅仅是一个标识的设置和读取,并不存在fetch-mod-set操作,所以,synchronized显得有点高射炮打蚊子了,这里仅仅使用volatile来保证线程可见性足够了。

 

因此,这段程序是线程安全的,但是并没有使用synchronized关键字,也就是说并不是所有的线程安全都需要同步保护的,以下总结了一些线程安全的真理:

  1. 不变量或者只读变量永远是线程安全的。
  2. 至少有一个或者多个线程写才会产生线程安全问题。
  3. 如果操作包含fetch-mod-get行为,则可能产生Race Condition, 例如:i++, if (i==0) {i ++}等。
  4. 如果读多,写少,考虑使用读写锁。
  5. 如果有非常高的并发性,请考虑使用无锁实现的数据结构,例如:Concurrent*等。
  6. 如果能使用CAS等操作,请不要使用重量级的锁。
  7. 控制锁的粒度尽量更细更小。