当前位置: 移动技术网 > 科技>办公>CPU > 线程(四)解决线程不安全问题

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

2020年07月29日  | 移动技术网科技  | 我要评论

一、何为线程不安全?

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

体会线程不安全:

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网