欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

线程(四)解决线程不安全问题

程序员文章站 2022-03-06 16:17:33
一、何为线程不安全?线程安全: 多线程并发执行时, 没有产生逻辑错误线程不安全: 多线程并发执行时, 产生逻辑错误体会线程不安全:static class Counter { public int count = 0; public void increase() { count++; // 自增操作步骤: // 1. 把内存中的数据读取到 CPU 中(load) // 2. CPU 中把数据加一(increase)...

一、何为线程不安全?

线程安全: 多线程并发执行时, 没有产生逻辑错误
线程不安全: 多线程并发执行时, 产生逻辑错误

体会线程不安全:

static class Counter {
   public int count = 0;

    public void increase() {
        count++;
        // 自增操作步骤:
        // 1. 把内存中的数据读取到 CPU 中(load)
        // 2. CPU 中把数据加一(increase)
        // 3. 把计算结束的数据传回内存中(save)
    }
	public static void main(String[] args) throws InterruptedException {
		Counter counter = new Counter();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    counter.increase();
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    counter.increase();
                }
            }
        };
        t1.start();
        t2.start();

        t1.join();
        t2.join();
        // 并发执行
        System.out.println(counter.count);
	}
}

线程 t1 与线程 t2 并发执行,则线程 t2 可能在线程 t1 执行自增操作期间的任何时刻进行自增操作,所以可能发生线程自增两次,结果却还是 1 的情况,这就是线程不安全。

可以总结出线程不安全的理由:

  1. 线程是抢占式执行的(线程 t1, t2 是抢占式执行的)
  2. 自增操作不是原子的(每次 ++ 都能拆分成三个步骤),
    执行任何一步时, 都可能被调度器调度走
  3. 多个线程尝试修改同一个变量(两线程同时修改 count, count 并没有增加)
  4. 内存可见性导致的线程安全问题 (防止编译器过度优化:出现一个线程读,一个线程写的情况)
  5. 指令重排序 (编译器在编译代码时, 会针对指令进行优化, 调整指令的运行顺序, 提升程序运行效率)

二、解决线程不安全:

  1. 给自增操作加 锁, 使其变为原子操作。
    锁的关键字: synchronized (英文原意: 同步)
    锁的特点: 互斥
    同一时刻只有一个线程能获取到锁, 其他尝试获取锁的线程会发生阻塞等待,
    一直到刚才获取了锁的线程释放锁, 剩下的线程才能重新竞争
    ps: 加锁(获取锁) lock 解锁(释放锁)unlock
  2. 关键字 volatile:
    保持内存可见性, 解决一个线程读,一个线程写的情况。
  3. 双重 if 保证效率

三、线程安全的具体实现
四、双重 if 实现(单例模式)

本文地址:https://blog.csdn.net/weixin_45975659/article/details/107621735