1、 什么是线程安全问题

我们使用多线程主要是为了提高应用程序的使用率,但同时会给我们带来很多线程安全问题。
多线程环境下,线程抢占CPU资源交替执行,一般他们会使用多个线程执行相同的代码。如果在这相同的代码里边有共享的变量,或者一些组合操作,我们想要正确的结果就很容易出现问题。
例如,我们模拟三个线程,同时去抢占资源,把资源类定义好的int count = 100,每执行一次减一,当count =0时,不再运行。

  1. package com.atguigu.myself.safe;
  2. public class CountInfo implements Runnable {
  3. private int count = 100;
  4. @Override
  5. public void run() {
  6. while (true) {
  7. if (count > 0) {
  8. try {
  9. Thread.sleep(100);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. System.out.println(Thread.currentThread().getName()+"现在是"+count--);
  14. } else {
  15. break;
  16. }
  17. }
  18. }
  19. }
package com.atguigu.myself.safe;

public class SafeTest {

    public static void main(String[] args) {

        CountInfo countInfo = new CountInfo();

        new Thread(countInfo).start();
        new Thread(countInfo).start();
        new Thread(countInfo).start();

    }

}

运行测试类,会发现,有些count被打印执行了两次,甚至会出现count为-1的情况。
这里,count—是个复合操作,它会先读取count值,然后将count给代码中运行,最后再将count值-1。在多线程情况下,可能线程1读取到count值为1的时候,盘点count>0是满足的,
就进入if判断的逻辑中,但是此时线程2甚至线程3都获取道count为1,都进入道if判断的逻辑中,各自都给count-1。这就是一种线程安全问题。

2、 线程安全解决思路

一般采用下面几种方法来解决线程安全问题:

  • 无状态,即没有共享变量;
  • 使用final使共享变量不可变;
  • 加锁;
  • 使用JDK为我们提供的类来实现线程安全
  • 其他;