ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线程之间的通信

2021-12-30 20:32:42  阅读:147  来源: 互联网

标签:bottles 通信 milk 线程 之间 方法 public Milk


线程之间的通信

使用线程来运行多个任务时,可以通过使用锁来同步俩个任务的行为,从而使得一个任务不会干扰到另外一个任务,这是解决线程间彼此干涉的问题,现在我们需要来解决线程间彼此协调的问题问题,也就是线程之间通信的问题。–摘自百度

其实我在工作的期间一直对线程这个概念并不是很清晰,只要不是单独线程独立运行的话,就都会涉及线程之间的交互,那么就属于线程之间通信

  • join:一个线程让另外一个线程参见进来执行完成
  • 生产者/消费者:是生产者和消费者之间的协调

一 wait 和notify/notifyAll

在进行本小节的深入探讨的之前,我想抛出一个问题:什么是线程通信
多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或者操作。换句简单的话来描述就是说:多个线程在操作同一份数据时,避免对同一个变量进行操作从而造成变量资源的争夺。
那么在面对这个问题的时候,我们就会想到,要是其中一个线程能睡着然后等休息好了,在对任务进行操作,这样就不会争抢而且还会有一种井然有序的感觉。
这样的话我们就引出唤醒机制:(wait(),notify())
就是在一个线程进行规定操作后,那么我就进入等待状态(wait),然后等其他线程将指定的任务完成之后,在将线程唤醒(notify)。

wait()方法

在其他线程调用对象时的notify方法或者 notifyAll方法前,那么我当前的线程就会等待。
线程调用wait()方法得时候,就会释放他对锁的拥有权,然后等待另外的线程来通知它,当然,唤醒线程的方式不可能是_‘喂!你该起来上班啦!!!’_他是有固定方法的。比如notifynotifyAll方法,使用这俩个方法才可以获得锁的拥有权。
~注意
要确保调用wait()方法的时候拥有锁那么就得确保wait()方法的调用必须放在synchronized方法或synchronized块中。

notify()方法

notify()方法会唤醒一个等待当前对象锁的线程

notifyAll()方法

notifyAll()方法会唤醒此对象监视器上等待的所有线程

~注意
如果多个线程在等待,它们中的一个将会选择被唤醒。
这种选择是随意的,和具体实现有关。
notify()方法应该是被拥有对象的锁的线程所调用。
notifyAll()方法同理

二 线程实例

其实不难理解线程之间最好的实例就是:生产者消费者模型,那么我们就来仿写一个生产者消费者的例子;

生产牛奶的方法以及消费的方法

package ThreadDemo;

/**
 * Created by jdx on 2021/12/29 下午3:56
 */
public class Milk {
    //生产牛奶的奶牛编号
    private int cowsId;
    //牛奶
    private int bottles;

    //生产牛奶的方法
    public synchronized void MilkTheCow() {
        //当牛奶生产的牛奶瓶子数不为0时,那生产牛奶的方法就停止
        if (bottles != 0) {
            try {
                //等待线程
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //那么当我的牛奶瓶数为0的时候奶牛就开始产奶
        bottles = bottles + 1;
        //为了区别是哪一个牛产的哪一瓶奶那么奶牛编号也得区分一下
        cowsId = cowsId + 1;
        //获取生产奶的奶牛
        String cowName = Thread.currentThread().getName();
        //从控制台输出
        System.out.println(cowName + " 生产了一瓶编号为" + cowsId + " 牛奶");
        //从这时候开始,就得唤醒其他等待的线程
        notify();
    }

    //消耗牛奶的方法
    public synchronized void drinkMilk() {
        //当牛奶瓶数为0的时候,这个方法处于等待状态
        if (bottles == 0) {
            try {
                wait();
                //InterruptedException 是 wait sleep 等方法自己抛出的 '中断异常'
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //消费牛奶
        bottles = bottles - 1;
        //人作为消费者
        String people = Thread.currentThread().getName();
        //从控制台输出
        System.out.println(people + "喝了一个牛奶,编号为:" + cowsId);
        //执行完成之后 去唤醒其他线程
        notify();
    }
    //get set 方法


    public int getCowsId() {
        return cowsId;
    }

    public void setCowsId(int cowsId) {
        this.cowsId = cowsId;
    }

    public int getBottles() {
        return bottles;
    }

    public void setBottles(int bottles) {
        this.bottles = bottles;
    }
    //无参构造

    public Milk() {
        super();
    }

    //有参构造

    public Milk(int cowsId, int bottles) {
        super();
        this.cowsId = cowsId;
        this.bottles = bottles;
    }
}

生产牛奶的类

package ThreadDemo;

/**
 * Created by jdx on 2021/12/30 下午6:01
 */
public class cows extends Thread {
    //获得牛奶的类
    private Milk milk;

    //无参构造
    public cows() {
        super();
    }

    //有参构造
    public cows(Milk milk) {
        super();
        this.milk = milk;
    }

    //get set 方法
    public Milk getMilk() {
        return milk;
    }

    public void setMilk(Milk milk) {
        this.milk = milk;
    }
    //重写run方法

    @Override
    public void run() {
        productMilk();
    }

    private void productMilk() {
        //默认生产25瓶牛奶
        for (int i = 0; i < 2; i++) {
            //调用生产牛奶的方法
            milk.MilkTheCow();
        }
    }
}

消费牛奶的类

package ThreadDemo;

/**
 * Created by jdx on 2021/12/30 下午6:12
 */
public class people extends Thread {
    //获得牛奶的类
    private Milk milk;

    //get set 方法

    public Milk getMilk() {
        return milk;
    }

    public void setMilk(Milk milk) {
        this.milk = milk;
    }
    //重写run方法

    @Override
    public void run() {
        drink();
    }

    private void drink() {
        for (int i = 0; i < 2; i++) {
            //调用消费牛奶的方法
            milk.drinkMilk();
        }
    }


    //有参构造
    public people(Milk milk) {
        super();
        this.milk = milk;
    }

    //无参构造
    public people() {
        super();
    }

}

测试单元

package basics;

import ThreadDemo.Milk;
import ThreadDemo.cows;
import ThreadDemo.people;

/**
 * Created by jdx on 2021/12/30 下午6:17
 */
public class milkTest {
    public static void main(String[] args) {
        //new 一个 Milk 类
        Milk milk = new Milk();
        //new 一个 cows 类
        cows cow = new cows(milk);
        //new 一个 people 类
        people humanity = new people(milk);
        //new 一个 包含生产者的线程
        Thread threadCow = new Thread(cow, "生产者:奶牛");
        //new 一个 包含消费者的线程
        Thread threadHum = new Thread(cow, "消费者:人类");
        //启动线程
        threadCow.start();
        threadHum.start();
    }
}

多多感悟

标签:bottles,通信,milk,线程,之间,方法,public,Milk
来源: https://blog.csdn.net/weixin_46128463/article/details/122171778

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有