• 分享Java并发:线程间的通信


    线程间的通信

    JVM在运行时会将自己管理的内存区域,划分为不同的数据区,称为运行时数据区。每个线程都有自己私有的内存空间,如下图示:

    Java线程按照自己虚拟机栈中的方法代码一步一步的执行下去,在这一过程中不可避免的会使用到线程共享的内存区域堆或方法区。为了防止多个线程在同一时刻访问同一个内存地址,需要互相告知自己的状态以避免资源争夺。

    线程的通信方式主要分为三种方式:①共享内存②消息传递③管道流

    共享内存:线程之间通过对共享内存的读-写来实现隐式通信。Java中的具体实现是:volatile共享内存。

    消息传递:线程之间通过明确的发送消息来实现显示通信。Java中的具体实现是:等待/通知机制(wait/notify),join方法。

    管道流:管道输入/输出流。

    1、等待/通知机制

    其过程是:线程A由于某些原因,自主调用了对象o的wait方法,进入WAITING状态,释放占有的锁并等待通知。而线程B则调用对象o的notify方法或notifyall方法进行通知,线程A会收到通知,并从wait方法中返回,继续执行后面的代码。

    可以发现,线程A和线程B就是通过对象o的wait方法和notify方法来发送消息,进行通信。

    wait方法和notify方法是Object类的方法,而Object类是所有类的父类,因此所有对象都实现了Object类的方法。即所有的对象都具有wait方法和notify方法。

    由于线程的等待/通知机制需要借助共享对象,所以在调用wait方法前,线程必须先获得该对象的锁,即只能在同步方法或同步块(synchronized代码块)中调用wait方法,在调用wait方法后,线程释放锁。

    同样的notify方法在调用前也需要获得对象的锁,即也只能在同步方法或同步块中调用notify方法。若有多个线程在等待,则线程调度器会随机挑选一个线程来通知。需要注意的是,被通知的线程并不会在得到通知后就马上从wait方法返回,而是需要等待获得对象的锁后才能从wait方法返回。而调用了notify方法的线程也并不会在调用时就马上释放对象的锁,而是在执行完同步方法或同步块(synchronized代码块)后,才释放对象的锁。因此,被通知的线程要等调用了notify的线程释放锁后,才能从wait方法中返回。

    综上所述,等待/通知机制的经典范式如下:

    1. /**
    2. * 等待线程(调用wait方法的线程)
    3. */
    4. synchronized(共享对象){ //同步代码块,进入条件是获得锁
    5. while(判断条件){ //进行wait线程任务的条件不满足时进入
    6. 共享对象.wait()
    7. }
    8. 线程任务代码
    9. }
    10. /**
    11. * 通知线程(调用notify方法的线程)
    12. */
    13. synchronized(共享对象){ //同步代码块,进入条件是获得锁
    14. 线程任务代码
    15. 改变wait线程任务的条件
    16. 共享对象.notify()
    17. }

    根据以上范式,有代码如下:

    1. public class WaitNotify {
    2. static boolean flag = true; //等待线程继续执行往下执行的条件
    3. static Object lock = new Object(); //上锁的对象
    4. public static void main(String[] args) throws InterruptedException {
  • 相关阅读:
    MySQL-索引优化/查询优化
    Python学习:循环语句教程
    Linux安装Oracle数据库
    前大厂员工谈中美企业区别,中企不用单元测试,仅靠QA检查代码?
    MATLAB|不给糖果就捣蛋
    模型效果优化,试一下多种交叉验证的方法(系统实操)
    ccf序列查询新解python满分_纯数学规律(学霸怎么想到的啊......)
    Volatile:JVM 我警告你,我的人你别乱动!
    计算机网络 ——数据链路层(广域网)
    如何提高外贸独立站流量?
  • 原文地址:https://blog.csdn.net/Java_zhujia/article/details/127864216