• 【Java】详解多线程通信


    🌺个人主页:Dawn黎明开始

    🎀系列专栏:Java
    每日一句:什么都不做,才会来不及

    📢欢迎大家:关注🔍+点赞👍+评论📝+收藏⭐️


    文章目录

    🔐多线程通信

    (1).🔓由来

    (2).🔓成员方法 

    (3).🔓案例引入

    (4).🔓代码实现



    🔐多线程通信

    (1).🔓由来

          现代社会崇尚合作精神,分工合作在日常生活和工作中无处不在。举个简单的例子,例如一条生产线的上下两个工序,它们必须以规定的速率完成各自的工作,才能保证产品在流水线中顺利的流转。如果下工序过慢,会造成产品在两道工序之间的积压,如果上工序过慢,会造成下工序长时间无事可做。在多线程的程序中,上下工序可以看作两个线程,这两个线程之间需要协同完成工作,就需要线程之间进行通信。

    思路:

          如果想解决上述线程执行不一致的问题,就需要控制多个线程按照一定的顺序轮流执行,此时就需要让线程间进行通信保证线程任务的协调进行

    解决:

          为此,Java在Object类中提供了wait()notify()notifyAll()等方法用于解决线程间的通信问题,因为Java中所有类都是Object类的子类或间接子类,因此任何类的实例对象都可以直接使用这些方法。

    (2).🔓成员方法 

    说明:

         其中wait()方法用于使当前线程进入等待状态,notify()和notifyAll()方法用于唤醒当前处于等待状态的线程。

    注意:

         wait()、notify()和notifyAll()方法的调用者都应该是同步锁对象,如果这三个方法的调用者不是同步锁对象,Java虚拟机就会抛出IllegalMonitorStateException异常。 

    (3).🔓案例引入

    生产者-消费者问题分析:

      资源:product<=20

      前台店员:Clerk

      A:从生产者线程获取资源

      B:将资源卖给消费者线程

      生产资源:ProducerThread(生产者)

      消费资源:ConsumerThread(消费者)

      测试类:Demo

    (4).🔓代码实现

    分析:

          A:使用同步机制

          B:线程通信问题:通过Java提供的等待唤醒机制解决。

    Object类中提供了三个方法:

          wait():等待,释放锁资源

          notify():唤醒单个线程,从等待的位置继续执行

          notifyAll():唤醒所有线程

    代码如下👇🏻 

    1. package Pro;
    2. public class Clerk {
    3. private int product=20; //共享资源
    4. //从生产者线程获取资源
    5. public synchronized void addProduct(){
    6. if(product>=20){
    7. try {
    8. this.wait();//生产者线程等待,释放锁资源
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. }else{
    13. product++;
    14. System.out.println("生产者生产第" + product + "个产品");
    15. this.notifyAll();
    16. }
    17. }
    18. //将资源卖给消费者线程
    19. public synchronized void sellProduct(){
    20. if(product<=0){
    21. try {
    22. this.wait();//消费者线程等待,释放锁资源
    23. } catch (InterruptedException e) {
    24. e.printStackTrace();
    25. }
    26. }else{
    27. System.out.println("消费者消费第"+product+"个产品");
    28. product--;
    29. this.notifyAll();
    30. }
    31. }
    32. }
    1. package Pro;
    2. public class ProducerThread implements Runnable {
    3. Clerk clerk;
    4. public ProducerThread(Clerk clerk) {
    5. super();
    6. this.clerk = clerk;
    7. }
    8. @Override
    9. public void run() {
    10. while(true){
    11. clerk.addProduct();
    12. try {
    13. Thread.sleep((int)(Math.random()*10)*100);
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. }
    19. }
    1. package Pro;
    2. public class ConsumerThread implements Runnable {
    3. Clerk clerk;
    4. public ConsumerThread(Clerk clerk) {
    5. super();
    6. this.clerk = clerk;
    7. }
    8. @Override
    9. public void run() {
    10. while(true){
    11. clerk.sellProduct();
    12. try {
    13. Thread.sleep((int)(Math.random()*10)*100);
    14. } catch (InterruptedException e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. }
    19. }

    1. package Pro;
    2. public class Demo {
    3. public static void main(String[] args) {
    4. Clerk c=new Clerk();
    5. new Thread(new ProducerThread(c), "生产者线程甲").start();
    6. new Thread(new ProducerThread(c), "生产者线程乙").start();
    7. new Thread(new ConsumerThread(c),"消费者线程甲").start();
    8. new Thread(new ConsumerThread(c),"消费者线程乙").start();
    9. // ProducerThread pt =new ProducerThread(c);
    10. // Thread t1=new Thread(pt, "生产者线程甲");
    11. // Thread t2=new Thread(pt, "生产者线程乙");
    12. // ConsumerThread ct =new ConsumerThread(c);
    13. // Thread t3=new Thread(ct,"消费者线程甲");
    14. // Thread t4=new Thread(ct,"消费者线程乙");
    15. // t1.start();
    16. // t2.start();
    17. // t3.start();
    18. // t4.start();
    19. }
    20. }

    思考:

    为什么这些方法不定义在Thread类而是Object类中呢?

          这些方法的调用必须通过锁对象调用,而Object类对象代表任意的对象。所以,这些方法必须定义在Object类中。


    🌺建议大家亲自动手操作,学编程,多实践练习是提升编程技能的必经之路。

    🌺欢迎大家在评论区进行讨论和指正!

  • 相关阅读:
    element-ui 组件库 button 源码分析
    Gradle在Androidstudio中下载超时提示Download info Connect timed out
    【CSS】
    fastapi-Depends
    react antd InputNumber只允许输入数字的方法
    Persistent data structure 不可变数据结构
    java实现分类下拉树,点击时对应搜索---后端逻辑
    go语言数组、切片和指针
    《动态规划 ---- 线性规划一》----- 动态规划的基本概念,线性动态规划-->背包问题
    javascript函数式编程初探——什么是函数式编程?
  • 原文地址:https://blog.csdn.net/2301_80760873/article/details/134443550