线程间的通信

线程间通信的模型有两种:共享内存和消息传递
  线程通信其实就是 ,实现线程的交替工作,并传递信息

线程间的通信具体步骤:(涉及上中下部)

  1. 创建资源类,在资源类中船舰属性和操作方法
  2. 在资源类操作方法:判断、操作、通知
  3. 创建多个线程,调用资源类的操作方法
  4. 防止虚拟唤醒问题 (if 判读,只会判断一次)

 

1synchronized

操作线程的时候,等待线程使用wait()
通知另外的线程操作用notify()、notifyAll()
假设有两个线程,该线程在执行过程中,判断值(不是该值等待,让其他线程抢),操作值,通知另外一个线程的调度 

//第一步 创建资源类,定义属性和操作方法
class Share {
    //初始值
    private int num = 0;
    //+1的方法
    public synchronized void incr() throws InterruptedException {
        //第二步 判断 干活 通知
       if(number != 0) { //判断number值是否是0,如果不是0,等待
            this.wait(); //在哪里睡,就在哪里醒
        }
        //如果number值是0,就+1操作
        number++;
        System.out.println(Thread.currentThread().getName()+" :: "+num);
        //通知其他线程
        this.notifyAll(); //注意这里的通知是随机的,就是只能通知全部
    }
 
    //-1的方法
    public synchronized void decr() throws InterruptedException {
        //判断
        if(number != 1) {
            this.wait();
        }
        //干活
        number--;
        System.out.println(Thread.currentThread().getName()+" :: "+number);
        //通知其他线程
        this.notifyAll();
    }
}
 
public class ThreadDemo1 {
    //第三步 创建多个线程,调用资源类的操作方法
    public static void main(String[] args) {
        Share share = new Share();
        //创建线程
        new Thread(()->{
            for (int i = 1; i <=10; i++) {
                try {
                    share.incr(); //+1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"AA").start();
 
        new Thread(()->{
            for (int i = 1; i <=10; i++) {
                try {
                    share.decr(); //-1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"BB").start();
    }
}
 

2 Lock锁 

 使用lock先要创建锁的对象以及通知的对象
放置在资源类中

 
    private Lock lock= new ReentrantLock();   //创建可重锁
    private Condition  condition= lock.newCondition();
        //他能操作的对象

上锁 lock.lock();
解锁 lock.unlock();
以下都为 condition类:
唤醒所有等待的线程signalAll(),带上类名condition.signalAll();
唤醒一个等待线程signal(),带上类名,condition.signal();
造成当前线程在接到信号或者被中断之前一直处于等待状态await(),带上类名,condition.await();

3 生产者消费者模型 

  • 案例需求

    生产者消费者案例中包含的类:

    奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作

    生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作

    消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作

    测试类(BoxDemo):里面有main方法,main方法中的代码步骤如下

    ①创建奶箱对象,这是共享数据区域

    ②创建消费者创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作

    ③对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作

    ④创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递

    ⑤启动线程

  • public class Box {
        //定义一个成员变量,表示第x瓶奶
        private int milk;
        //定义一个成员变量,表示奶箱的状态
        private boolean state = false;
    
        //提供存储牛奶和获取牛奶的操作
        public synchronized void put(int milk) {
            //如果有牛奶,等待消费
            if(state) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            //如果没有牛奶,就生产牛奶
            this.milk = milk;
            System.out.println("送奶工将第" + this.milk + "瓶奶放入奶箱");
    
            //生产完毕之后,修改奶箱状态
            state = true;
    
            //唤醒其他等待的线程
            notifyAll();
        }
    
        public synchronized void get() {
            //如果没有牛奶,等待生产
            if(!state) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            //如果有牛奶,就消费牛奶
            System.out.println("用户拿到第" + this.milk + "瓶奶");
    
            //消费完毕之后,修改奶箱状态
            state = false;
    
            //唤醒其他等待的线程
            notifyAll();
        }
    }
    
    public class Producer implements Runnable {
        private Box b;
    
        public Producer(Box b) {
            this.b = b;
        }
    
        @Override
        public void run() {
            for(int i=1; i<=30; i++) {
                b.put(i);
            }
        }
    }
    
    public class Customer implements Runnable {
        private Box b;
    
        public Customer(Box b) {
            this.b = b;
        }
    
        @Override
        public void run() {
            while (true) {
                b.get();
            }
        }
    }
    
    public class BoxDemo {
        public static void main(String[] args) {
            //创建奶箱对象,这是共享数据区域
            Box b = new Box();
    
            //创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
            Producer p = new Producer(b);
            //创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
            Customer c = new Customer(b);
    
            //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
            Thread t1 = new Thread(p);
            Thread t2 = new Thread(c);
    
            //启动线程
            t1.start();
            t2.start();
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值