在Java多线程编程模型1里面讲到了为什么线程不安全,那怎样才能做到线程安全了?
先来看线程工作是跟内存是怎么打交道的。
在并发的线程中,分为主内存和工作内存,主内存就是程序分配的内存,工作内存就是线程所占的内存。线程可能在工作内存中存储了某些主内存对象的副本。当线程操作某个主内存的对象时,先从主内存中将变量的值拷贝到工作内存中,然后在工作内存中改变这个值,最后将这个值刷到主内存中。
在<<java concurrency in pratise>>中提出了线程安全的思路
1) 不要在线程间共享变量
2) 如果不行,就要final变量
3) 还是不行,就用volatile或其它并发控制。
其实基本的思路是尽量减少共享变量,如果实在要用,则需要并发控制。
那非要用的时候怎么办了,这个时候就需要拿出happens-before规则来检查多线程的程序了。
(1)同一个线程中的每个Action都happens-before于出现在其后的任何一个Action(Program order rule)
(2)对一个监视器的解锁happens-before于每一个后续对同一个监视器的加锁(Monitor lock rule)
(3)对volatile字段的写入操作happens-before于每一个后续的同一个字段的读(Volatile variable rule.)
(4)Thread.start()的调用会happens-before于启动线程里面的动作(Thread start rule.)
(5)Thread中的所有动作都happens-before于其他线程检查到此线程结束或者Thread.join()中返回或者Thread.isAlive()==false(Thread termination rule.)
(6)一个线程A调用另一个线程B的interrupt()都happens-before于线程A发现B被A中断(B抛出异常或者A检测到B的isInterrupted()或者interrupted())(Interruption rule)
(7)一个对象构造函数的结束happens-before于该对象的finalizer的开始(Finalizer rule.)
(8)如果A动作happens-before于B动作,而B动作happens-before与C动作,那么A动作happens-before于C动作(Transitivity)
如果你的程序能够满足上面的发则,那么恭喜你,不会在出现并发的问题了。