目录
1.什么是线程安全?
2.造成线程不安全的原因
3.线程不安全的解决方案
1.synchronized关键字——监视器锁monitor lock
2.volatile关键字
3.wait和notify
1.什么是线程安全?
在操作系统中,因为线程的调度是随机的(抢占式执行),正是因为这种随机性,才会让代码中产生很多bug。如果认为是因为这样的线程调度才导致代码产生了bug,则认为线程是不安全的。
如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。
2.造成线程不安全的原因
- 抢占式执行,调度过程随机
- 多个线程同时修改一个变量
- 针对变量的操作没有保证原子性
- 内存可见性,一个线程频繁读,一个线程频繁写
- 代码指令重排序
3.线程不安全的解决方案
1.synchronized关键字——监视器锁monitor lock
1.synchronized关键字——监视器锁monitor lock
作用:
- 多个线程,使用同一个对象进行加锁(基于对象头加锁),可以实现线程间的同步互斥
- 原子性:互斥就能满足原子性(某个线程执行同一个对象加锁的同步代码,排斥另一个线程加锁,满足最小执行单位)
- 可见性:synchronized结束释放锁,会把工作内存中的数据刷新到主存;其他线程申请锁,获取的始终是最新的数据(满足可见性)
- 有序性:某个线程执行一段同步代码,不管如何重排序,过程中不可能有其他线程执行的指令,这样多个线程执行同步代码,就能满足一定的顺序(满足有序性)
- 可重入性:同一个线程,可以多次申请同一个对象锁
2.volatile关键字
作用:
- 保证可见性:多个线程对同一个变量的操作,具有可见性
- 禁止指令重排序,建立内存屏障
注意:不保证原子性操作
使用场景:共享变量的读操作及常数赋值操作
原因:这些操作本身就具有原子性
3.wait和notify
由于线程之间是抢占式执行的,因此线程之间执行的顺序难以预知,因此我们需要合理的协调多个线程之间的执行先后顺序。
wait 做的事情:- 使当前执行代码的线程进行等待. (把线程放到等待队列中)
- 释放当前的锁
- 满足一定条件时被唤醒, 重新尝试获取这个锁.
- 其他线程调用该对象的 notify 方法.
- wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
- 其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.
- 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其 它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
- 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到")
- 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行 完,也就是退出同步代码块之后才会释放对象锁。



