线程安全问题重点

Posted 一朵花花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全问题重点相关的知识,希望对你有一定的参考价值。

线程安全

线程安全问题是多线程所涉及到的最重要的,也是最复杂的问题

观察线程不安全

public class ThreadDemo14 
    static class Counter
        public int count = 0;
        public void increase()
            count++;
        
    
    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 < 50000; i++) 
                    counter.increase();
                
            
        ;
        t1.start();

        Thread t2 = new Thread()
            @Override
            public void run()
                for (int i = 0; i < 50000; i++) 
                    counter.increase();
                
            
        ;
        t2.start();
        t1.join();
        t2.join();
        // 两个线程各自自增5000次,最终预期结果,应该是10w
        System.out.println(counter.count);
    

注意:

运行结果:


多运行几次你会发现,结果并不是10w,而且每次运行的结果都不一样
上述现象:则是线程不安全
线程不安全: 多线程并发执行某个代码时,产生了逻辑上的错误,就是"线程不安全"

线程安全的概念

和线程不安全对应,线程安全就是 多线程并发执行某个代码,没有逻辑上的错误,就是"线程安全"

线程不安全的原因

思考: 为啥会出现上述情况???

原因:

  • 线程是抢占式执行的 (线程不安全的万恶之源)
    抢占执行:线程之间的调度完全由内核负责,用户代码中感知不到,也无法控制
    线程之间谁先执行,谁后执行,谁执行到哪里从CPU上下来,这样的过程都是用户无法控制的,也是无法感知的
  • 自增操作不是原子的
    每次++,都能拆分成三个步骤:
    1.把内存中的数据读取到CPU中 — load
    2.在CPU中,把数据+1 — increase
    3.把计算结束的数据写回到内存中 — save
    当CPU执行到上边三个步骤的任意一个步骤时,都可能被调度器调度走,让给其他线程来执行

画图表示:
上述代码的执行结果在范围 [5w,10w] 之间
极端情况下,
t1 和 t2 每次++ 都是纯并行的,结果就是 5w
t1 和 t2 每次++ 都是纯串行的,结果就是 10w
实际情况,一般不会这么极端,调度过程中有时候是并行,有时候是串行(多少次并行,多少次串行,这个不清楚),因此导致最终的结果是在 [5w,10w] 之间

  • 多个线程尝试修改同一个变量
    若一个线程修改一个变量,线程安全
    若多个线程尝试读取同一个变量,线程安全
    若多个线程尝试修改不同的变量,线程安全
  • 内存可见性
  • 指令重排序
    Java 的编译器在编译代码时,会针对指令进行优化 (优化:调整指令的先后顺序,保证原有逻辑不变的情况下, 来提高程序的运行效率)

如何解决线程不安全问题?

1.抢占式执行 — (这个没法解决,操作系统内核解决)
2.自增操作非原子 — (这个有办法,可以给自增操作加上锁) 适用范围最广
3.多个线程同时修改同一个变量 — (这个不一定有办法解决,得看具体的需求)

转下篇:

以上是关于线程安全问题重点的主要内容,如果未能解决你的问题,请参考以下文章

线程安全问题重点

线程安全问题重点

为啥基于锁的程序不能组成正确的线程安全片段?

Java中的线程安全问题(多线程重点)

Java中的线程安全问题(多线程重点)

Java中的线程安全问题(多线程重点)