• 线程--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("------------------------------------------------------
    ");
                    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才能从休眠状态变为运行状态

  • 相关阅读:
    bzoj 2257 (JSOI 2009) 瓶子与燃料
    bzoj 2257 (JSOI 2009) 瓶子与燃料
    splay 模板 洛谷3369
    费用流 模板 洛谷3381
    bzoj 1024 [SCOI2009]生日快乐——模拟
    bzoj 3231 [Sdoi2008]递归数列——矩阵乘法
    hdu 5823 color II——子集dp(独立集)
    bzoj 1093 [ZJOI2007]最大半连通子图——缩点+拓扑
    洛谷 3959 宝藏——枚举+状压dp
    bzoj 1034 [ZJOI2008]泡泡堂BNB——贪心
  • 原文地址:https://www.cnblogs.com/xiaoaiying/p/13696294.html
Copyright © 2020-2023  润新知