多线程进阶-线程安全问题 Synchronized详细讲解
2024-07-06多线程进阶-线程安全问题
1.多线程带来的的风险-线程安全 (重点)
1.1观察线程不安全
1.2产生线程安全问题原因:
1.3解决上述问题的办法:加锁
2.关键字-监视器锁monitor lock
2.1 synchronized 的特性
(1) 互斥
(2) 刷新内存
(3) 可重入
2.2 synchronized 使用示例
(1) 直接修饰普通方法: 锁的 SynchronizedDemo 对象
(2) 修饰静态方法: 锁的 SynchronizedDemo 类的对象
(3) 修饰代码块: 明确指定锁哪个对象.
锁类对象
3.死锁
3.1常见的死锁
3.2死锁的成因
3.3解决死锁的方法
1.多线程带来的的风险-线程安全 (重点)
1.1观察线程不安全
线程安全是整个多线程中,最复杂的部分,也是最重要的部分。 在单个线程环境下,执行完全正确但是如果同样的代码,让多个线程去同时执行此时就可能会出现bug这就是“线程安全问题”/“线程不安全”
static class Counter {
public int count = 0;
void increase() {
count++;
}
}
public static void main(String[] args) throws InterruptedException {
final Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter.count);
}
运行结果
预期结果两个线程各增5w次,最后count=10w 实际结果和10w差别很大
for (int i = 0; i < 50000; i++) {
counter.increase();
}
这个代码,在单线程中执行100%正确,但是,两个线程,并发的进行上述循环,此时逻辑就可能出现问题。
count++ 这个操作,本质上,是分成三步进行的~~
站在cpu的角度上,count++ 是由 cpu 通过三个指令来实现的~~
(1)load 把数据从内存,读到cpu寄存器中 (2)add 把寄存器中的数据进行+ 1 (3)save 把寄存器中的数据,保存到内存中 如果是多个线程执行上述代码,由于线程之间的调度顺序,是"随机"的,就会导致在有些调度顺序下,上述的逻辑就会出现问题.
此处,这两个线程执行count++中间会产生多少种不同的执行顺序的情况?? 排列组合问题 此处其实是 无数种 !!! 因为也可能存在,t1执行一次count++的时候,t2执行了两次或者t1执行一次count++,t2执行了三次… 结合上述讨论,就意识