线程之间如何通信?
java 线程通信是将多个独立的线程个体进行关联处理,使得线程与线程之间能够进行相互通信。比如线程 A 修改了对象的值,然后通知给线程 B,使线程 B 能够知道线程 A 修改的值,这就是线程通信。
volatile
volatile 是轻量级的同步机制,volatile 保证变量对所有线程的可见性,不保证原子性。
- 当对 volatile 变量进行写操作的时候,JVM 会向处理器发送一条 LOCK 前缀的指令,将该变量所在缓存行的数据写回系统的内存。
- 由于缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己的缓存是不是过期了,当处理器发现自己的缓存行对应的内存地址被修改,就会将当前处理器的缓存行置为无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存中。
MESI(缓存一致性协议):当 CPU 写数据时,如果发现操作的变量是共享变量,即在其他 CPU 中也存在该变量的副本,会发出信号通知其他 CPU 将该变量的缓存行置为无效状态,因此当其他 CPU 需要读取这个变量时,就会从内存重新读取。
volatile 关键字的两个作用: - 保证了不同线程对共享变量进行操作时的可见性。即一个线程修改了某个变量的值,新的值对其他线程来说是立即可见的。
- 禁止指令重排。
指令重排序是 JVM 为了优化指令,提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。Java 编译器会在生成指令系列时在适当的位置插入 内存屏障 指令来禁止处理器重排序。插入一个内存屏障,相当于告诉 CPU 和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。对一个 volatile 字段进行写操作,Java 内存模型将在写操作后插入一个写屏障指令,这个指令会把之前的写入值都刷新到内存中。
synchronized
wait/notify(等待通知)机制
一个线程调用 Object 的 wait() 方法,使其线程被阻塞;另一个线程调用 Object 的 notify()/notifyAll() 方法,wait() 阻塞的线程继续执行。
● wait():让当前线程释放对象锁并进入等待(阻塞)状态。
● notify():唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到 CPU 的执行。
● notifyAll():唤醒所有正在等待相应对象锁的线程,使它们进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到 CPU 的执行。