线程(四)解决线程不安全问题
程序员文章站
2022-03-06 16:17:33
一、何为线程不安全?线程安全: 多线程并发执行时, 没有产生逻辑错误线程不安全: 多线程并发执行时, 产生逻辑错误体会线程不安全:static class Counter { public int count = 0; public void increase() { count++; // 自增操作步骤: // 1. 把内存中的数据读取到 CPU 中(load) // 2. CPU 中把数据加一(increase)...
一、何为线程不安全?
线程安全: 多线程并发执行时, 没有产生逻辑错误
线程不安全: 多线程并发执行时, 产生逻辑错误
体会线程不安全:
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 的情况,这就是线程不安全。
可以总结出线程不安全的理由:
- 线程是抢占式执行的(线程 t1, t2 是抢占式执行的)
- 自增操作不是原子的(每次 ++ 都能拆分成三个步骤),
执行任何一步时, 都可能被调度器调度走 - 多个线程尝试修改同一个变量(两线程同时修改 count, count 并没有增加)
- 内存可见性导致的线程安全问题 (防止编译器过度优化:出现一个线程读,一个线程写的情况)
- 指令重排序 (编译器在编译代码时, 会针对指令进行优化, 调整指令的运行顺序, 提升程序运行效率)
二、解决线程不安全:
- 给自增操作加 锁, 使其变为原子操作。
锁的关键字: synchronized (英文原意: 同步)
锁的特点: 互斥
同一时刻只有一个线程能获取到锁, 其他尝试获取锁的线程会发生阻塞等待,
一直到刚才获取了锁的线程释放锁, 剩下的线程才能重新竞争
ps: 加锁(获取锁) lock 解锁(释放锁)unlock - 关键字 volatile:
保持内存可见性, 解决一个线程读,一个线程写的情况。 - 双重 if 保证效率
本文地址:https://blog.csdn.net/weixin_45975659/article/details/107621735