如何实现线程间的数据安全?
线程安全在三个方面体现1.原子性 2.可见性 3.有序性
1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作
Java中提供了很多atomic类,AtomicInteger,AtomicLong,AtomicBoolean等 。
2.可见性:一个线程对主内存的修改可以及时的被其他线程看到
对于可见性,JVM提供了synchronized和volatile.
volatile的可见性是通过内存屏障和禁止重排实现的,volatile会在写操作时,在写操作后加一条store屏障指令,将本地内存中给共享变量值刷新到主内存。
Volatile在进行读操作时,会在读操作前加一条load指令,从内存中读取共享变量。
但是volatile不是原子性操作,对++操作不是安全的,不适合计数。Volatile适用于状态标记量。
3.有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,改观察结果一般杂乱无序。可以通过volatile、synchronized、lock保证有序性。
Happens-before原则:
(1)程序次序规则:在一个单独的线程中,按照程序代码书写的顺序执行
(2)锁定规则:一个unlock操作happen-before后面对同一个锁的lock操作
(3)Volatile变量规则:对一个volatile变量的血操作happen-befor后面对该变量的读操作
(4)线程启动规则:Tread对象的start()方法happen-before此线程的每一个动作
(5)线程终止规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
(6)线程中断规则:对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。
(7)对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。
(8)传递性:如果操作A happen—before操作B,操作B happen—before操作C,那么可以得出A happen—before操作C。