目录
什么是线程安全
整个多线程中最最重要、最最复杂的部分
什么是线程安全问题?
有些代码在单线程环境下执行,完全正确
让多个线程同时执行,此时就可能会出现bug
Thread t1 = new Thread(() -> {
// 对 count 变量进行自增 5w 次
for (int i = 0; i < 50000; i++) {
synchronized (locker) {
count++;
}
}
});
Thread t2 = new Thread(() -> {
// 对 count 变量进行自增 5w 次
for (int i = 0; i < 50000; i++) {
synchronized (locker) {
count++;
}
}
});
t1.start();
t2.start();
// 如果没有这俩 join, 肯定不行的. 线程还没自增完, 就开始打印了. 很可能打印出来的 count 就是个 0
t1.join();
t2.join();
// 预期结果应该是 10w
System.out.println("count: " + count);
但是打印的结果小于10000
原因:
count++ 这个操作,本质上,是分成三步进行的
①load 把数据从内存,读到 cpu 寄存器中,
②add把寄存器中的数据进行 +1
③save 把寄存器中的数据,保存到内存中如果是多个线程执行上述代码,由于线程之间的调度顺序,是"随机"的,就会导致在有些调度顺序下,上述的逻辑就会出现问题
所以,多线程中,最困难的一点就是线程的随机调度,使两个线程执行逻辑的先后顺序,存在诸多可能我们必须要保证在所有可能的情况下,代码都是正确的!!!
产生线程安全问题的原因:
①操作系统中,线程的调度顺序是随机的 (抢占式执行).罪魁祸首,万恶之源
②两个线程,针对同一个变量进行修改
a一个线程针对一个变量线程修改 ok
b两个线程针对不同变量修改 ok
c两个线程针对一个变量读取 ok
③修改操作,不是原子的.
类似的,如果一段逻辑中,需要根据一定的条件来决定是否修改
④内存可见性问题.
⑤指令重排序问题.