线程安全
一、定义
当多个线程访问某个类,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类为线程安全的。
二、先行发生原则 happens-before
判断数据是否有竞争、线程是否安全的主要依据
- 程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说是控制流顺序,因为要考虑到分支和循环结构。
- 管程锁定规则:一个unlock操作先行发生于后面(时间上)对同一个锁的lock操作。
- volatile变量规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作。
- 线程启动规则:Thread的start( )方法先行发生于这个线程的每一个操作。
- 线程终止规则:线程的所有操作都先行于此线程的终止检测。可以通过Thread.join( )方法结束、Thread.isAlive( )的返回值等手段检测线程的终止。
- 线程中断规则:对线程interrupt( )方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupt( )方法检测线程是否中断
- 对象终结规则:一个对象的初始化完成先行于发生它的finalize()方法的开始。
- 传递性:如果操作A先行于操作B,操作B先行于操作C,那么操作A先行于操作C。
三、线程不安全的定义
线程不安全:根据多线程并发访问时,得不到正确的结果,如多线程下对共享资源进行操作。
四、java非线程安全
如多线程对共享变量number进行number++操作;
number++ 不是原子性操作,被拆分成好几个步骤,在多线程并发执行的情况下,因为cpu调度,多线程快递切换,有可能两个同一时刻都读取了同一个number值,之后对它进行+1操作,导致线程安全性。
五、线程安全的原因
- 多线程环境
- 多个线程操作同一共享资源
- 对该共享资源进行了非原子性操作
六、避免线程安全
- 多线程环境:将多线程改单线程(必要的代码,加锁访问)
- 多个线程操作同一共享资源:不共享资源(ThreadLocal、不共享、操作无状态化、不可变)
- 对该共享资源进行了非原子性操作:将非原子性操作改成原子性操作(加锁、使用JDK自带的原子性操作的类、JUC提供的相应的并发工具类)