线程不安全的原因与解决方案
怎么导致的count<10_0000
加锁
多线程-可以让我们更充分利用多核CPU
但是 多线程有风险!!!!! 它不安全
咱们来看一个代码~~
class Counter{
public int count;
public void increase(){
count++;
}
}
public class Text {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread thread1 = new Thread(()-> {
for (int i = 0; i < 5_0000; i++) {
counter.increase();
}
});
Thread thread2 = new Thread(()-> {
for (int i = 0; i < 5_0000; i++) {
counter.increase();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(counter.count);
}
}
这个代码就是让 两个线程 各重复count加加5_0000次 最终求count
那答案你肯定觉得是 10_0000 ---然鹅
这就是线程不安全
那我们讲讲 线程不安全的原因与解决方案:
1.抢占式执行: 内核实现的
简单来说 你并不知道 那个线程什么时候执行,多个线程调度的时候,随机-无规律(导致写代码的时候需要思考,任意一种调度执行,都能运算出正确结果(敲重点:讲过)
2.多个线程修改一个变量: 有的时候可调整代码,但普遍性不高
3.修改操作不属于原子的: 解决线程安全,最常见的办法,把多个操作 通过特殊手段,打包成一个原子的操作
4.内存可见性问题: JVM的代码优化引入的bug
5.指令重排序:
从上述看 我们利用3 进行解决线程问题
更详细的说 加锁
那我们先解释 为什么 上上述代码和不是10_0000
因为 进行count++操作 底层是三条指令在 CPU上完成的 load add save
而当前两个线程修一个变量
而每一次修改需要三个步骤
这是不是 就和我上述线程不安全原因3吻合了
但是 你应该还是不理解 为什么count不等于10_0000 我之前也不理解 但是!看我给你画个图
这是正常操作 但是!
这就导致 为什么count小
再来看看加锁
加锁:就是让程序 '串行'
是让 thread1执行完 才能执行thread2
这就是 解决问题的一个思路~~