Skip to content

线程安全

一、定义

当多个线程访问某个类,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类为线程安全的。

二、先行发生原则 happens-before

判断数据是否有竞争、线程是否安全的主要依据

  1. 程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说是控制流顺序,因为要考虑到分支和循环结构。
  2. 管程锁定规则:一个unlock操作先行发生于后面(时间上)对同一个锁的lock操作。
  3. volatile变量规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作。
  4. 线程启动规则:Thread的start( )方法先行发生于这个线程的每一个操作。
  5. 线程终止规则:线程的所有操作都先行于此线程的终止检测。可以通过Thread.join( )方法结束、Thread.isAlive( )的返回值等手段检测线程的终止。
  6. 线程中断规则:对线程interrupt( )方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupt( )方法检测线程是否中断
  7. 对象终结规则:一个对象的初始化完成先行于发生它的finalize()方法的开始。
  8. 传递性:如果操作A先行于操作B,操作B先行于操作C,那么操作A先行于操作C。

三、线程不安全的定义

线程不安全:根据多线程并发访问时,得不到正确的结果,如多线程下对共享资源进行操作。

四、java非线程安全

如多线程对共享变量number进行number++操作;

number++ 不是原子性操作,被拆分成好几个步骤,在多线程并发执行的情况下,因为cpu调度,多线程快递切换,有可能两个同一时刻都读取了同一个number值,之后对它进行+1操作,导致线程安全性。

五、线程安全的原因

  • 多线程环境
  • 多个线程操作同一共享资源
  • 对该共享资源进行了非原子性操作

六、避免线程安全

  • 多线程环境:将多线程改单线程(必要的代码,加锁访问)
  • 多个线程操作同一共享资源:不共享资源(ThreadLocal、不共享、操作无状态化、不可变)
  • 对该共享资源进行了非原子性操作:将非原子性操作改成原子性操作(加锁、使用JDK自带的原子性操作的类、JUC提供的相应的并发工具类)