线程--2

多线程间通信

同步:多个线程对同一个资源的相同操作,同步即保证数据安全。
通信:多个线程对同一个资源(共享资源)不同操作。需要进行通信,保证数据安全问题

  • 多个线程使用同一个run方法,通过synchronize锁资源实现同步

  • 多个线程使用的不同的run方法,即生产者和消费者,通过通信来保证安全问题

  • 生产者与消费者模式

多线程通信---生产者和消费者。 考虑线程安全问题

  • 生产者:发布资源。如写
  • 消费者:利用资源。如读
package com.xiaoai.thread;

/**
 * 生成者消费者
 */

//资源
class  Res {
    public String userName;
    public String sex;
}

//生产
class  Out extends Thread{
    Res res;
    public Out(Res res){
        this.res = res;
    }
    @Override
    public void run() {
        //写操作 
        int count=0;
        while (true){
            if (count==0){
                res.userName = "xiaoai"; //1--生产线程到这里改变了资源姓名,还未修改性别,同时消费线程直接执行打印了资源信息
                res.sex = "男";
            }else {
                res.userName = "honghong";
                res.sex="女";
            }
            //计算奇数或偶数  使上面写出不同数据
            count = (count+1)%2;
        }
    }
}

//消费
class Input extends Thread{
    Res res;
    public Input(Res res){
       this.res = res;
    }
    @Override
    public void run() {
        while (true){
            //2--消费线程同时运行,打印了userName=xiaoai,但是生成线程还没有修改好性别,此时sex=女,然后这里直接打印了,所以出现了:xiaoai--女
            System.out.println(res.userName+"--"+res.sex);
        }
    }
}
public class OutInputThread {
    public static void main(String[] args){
        Res res = new Res();
        Out out = new Out(res);  //生产线程
        Input input = new Input(res); //消费线程

        out.start();
        input.start();
    }
}
  • 解决1:要使用同一锁 用this锁不行,因为不是同一个run即不是同一个this 锁同一个资源(即res)可以,但是有点问题。即不会写一个读一个,或者会重复读取一个相同的数据
  • 解决2:生产一个,消费一个,没有生产即不可消费,消费没完则不可生产

wait():让当前线程从运行状态变为休眠状态 即:立即释放锁的资源
notify():让当前线程从休眠状态变为运行状态 即:唤醒另一个线程 必须是同一个锁的资源才能唤醒
notifyAll():唤醒所有等待中的线程
ps:需要同步才能使用,而且要是同一个锁的资源 一般wait()和notify()一起使用 wait和notify只能在synchronized使用

package com.xiaoai.thread;

/**
 * 生成者消费者
 */

//资源 ---包子
class  Res {
    public String pi;  //包子皮
    public String xian; //馅料
    //标志位  true==生产者线程进行等待,消费者可以消费  false==生产者线程进行生产,消费者线程进行等待
    public boolean flag = false;  //有资源=true 没有资源=false
}

//生产者
class  Out extends Thread{
    Res res;
    public Out(Res res){
        this.res = res;
    }

    @Override
    public void run() {
        //生产操作
        int count=0;
        while (true){
            synchronized (res){
                if (res.flag){  //flag==true  有资源,无法生产,所以生产者需要等待
                    try {
                        res.wait(); //表示让当前线程从运行状态变成休眠状态 并且释放锁的资源
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (count==0){
                    res.pi = "薄皮"; //1--生产线程到这里改变了皮,还未修改馅,同时消费线程直接执行打印了资源信息
                    res.xian = "猪肉馅";
                }else {
                    res.pi = "冰皮";
                    res.xian="绿豆馅";
                }
                count = (count+1)%2; //计算奇数或偶数 实现生产不同数据

                System.out.println("生产者生产了-"+res.pi+res.xian+"-包子");
                //----------生产完成,可以消费
                System.out.println("-----------生产了-"+res.pi+res.xian+"-包子,可以消费");
                res.flag = true;//修改标志位,表示写完了,有资源了,提示消费者消费
                res.notify(); // 唤醒消费者线程
            }
        }
    }
}

//消费者
class Input extends Thread{
    Res res;
    public Input(Res res){
       this.res = res;
    }
    @Override
    public void run() {
        //消费操作
        while (true){
            synchronized (res){
                if (!res.flag){  //flag==false 没有资源,无法消费,所以消费者需要等待
                    try {
                        res.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //2--消费线程同时运行,打印了皮=薄皮,但是生成线程还没有修改好馅,此时性别还为绿豆馅,然后这里直接打印了,所以出现了:薄皮绿豆馅包子
                System.out.println("消费者消费了-"+res.pi+res.xian+"-包子");
                //----------消费完了,可以生产
                System.out.println("-----------消费了-"+res.pi+res.xian+"-包子,可以生产");
                System.out.println("------------------------------------------------------\n");
                res.flag = false; //修改标志位,告知消费完了,没有资源了消费了,提醒生产者生产
                res.notify(); //唤醒生产者线程
            }
        }
    }
}
public class OutInputThread {
    public static void main(String[] args){
        Res res = new Res();
        Out out = new Out(res);
        Input input = new Input(res);

        out.start();
        input.start();
    }
}

  • wait和sleep的区别?

作用都是做休眠
wait用于同步中可以释放锁的资源,sleep不会释放锁的资源,sleep只有等时间到期才从休眠状态变为运行状态。
wait需要notify才能从休眠状态变为运行状态

posted @ 2020-11-29 14:33  小艾影  阅读(66)  评论(0编辑  收藏  举报