Java线程通信+生产者消费者问题

新的笔记,继续冲!!!随手整理的,有错误的话轻喷,谢谢,哈哈哈。

先从问题引入:使用两个线程打印1-100,线程1、线程2交替打印。
首先分析一下:这是一个多线程问题,就要涉及到线程的安全,看过前面的博客,再来实现这个问题肯定不难,但是还要满足交替这个条件,这就要通过线程之间的通信来解决。线程1打印完一个就要通知线程2来打印。

1.涉及的方法
  1. wait():当前线程阻塞,释放同步监视器
  2. notify():唤醒一个被阻塞的线程。如果有多个线程被阻塞,唤醒优先级高的(相同则随机
  3. notifyall():唤醒全部阻塞的线程
2.方法的说明
  1. wait(),notify(),notifyall()只能在同步代码块或者同步方法中,Lock锁的通信有其他方法。
  2. 三个方法的调用者必须是同步代码块或同步方法中的同步监视器(保持一致即可),不然IllegalMonitorStateException。
  3. 这三个方法定义在java.lang.Object类中。既然任何对象都可以充当同步监视器,干脆就声明在Object中咯。
3.交替打印数-实现代码
class Number implements Runnable{
    private int number = 1;
    @Override
    public void run() {
        while (true){
            synchronized (this) {

                notify();
                if(number<=100){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;

                    try {
                        //使得调用如下wait()方法的线程阻塞,并释放监视器(锁)
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }//a执行完放开锁,a和b谁抢到了执行
        }
    }
}

public class ThreadMessage {
    public static void main(String[] args) {
        Number num = new Number();

        Thread t1 = new Thread(num);
        Thread t2 = new Thread(num);

        t1.setName("线程1");
        t2.setName("线程2");

        t1.start();
        t2.start();
    }
}
4.生产者消费者问题剖析

生产者(Producer)将产品交给店员(Clerk),而消费者(Consumer)从店员处取走产品,店员只能持有固定数量的产品(20),如果消费者试图生产过多的产品,店员会叫生产者停一下,有了空位再继续生产;如果店里没有产品了,店员会叫消费者等一下,有货了再来取走产品。

分析:

  1. 是否涉及到多线程问题? 是,生产者线程,消费者线程
  2. 是否有共享数据? 是,店员持有的数量
  3. 如何解决线程安全问题? 同步机制,三种方法
  4. 是否涉及线程的通信? 是
5.生产者消费者问题-代码实现
public class ProducerAndConsumer {
    public static void main(String[] args) {
        //共享数据在Clerk中,至始至终只创建了一个clerk,对于同步方法拿到的默认
        //同步监视器this(回顾一下),可以知道生产者和消费者是同一个监视器。
        Clerk clerk = new Clerk();

        Producer p1 = new Producer(clerk);
        p1.setName("生产者1");

        Consumer c1 = new Consumer(clerk);
        c1.setName("消费者1");

        p1.start();
        c1.start();
    }
}

class Clerk{
    private int ProductCount = 0;
    //生产产品
    public synchronized void AddCount() {
        
        if(ProductCount < 20){
            ProductCount++;
            System.out.println(Thread.currentThread().getName() + "开始生产第" + ProductCount + "个产品");

            notify();//生产一个就可以唤醒生产者开始消费了
        }else {//等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }       
    }
    //消费产品
    public synchronized void SubCount() {
        if(ProductCount > 0){
            System.out.println(Thread.currentThread().getName() + "开始消费第" + ProductCount + "个产品");
            ProductCount--;

            notify();//消费一个就可以唤醒生产者开始生产了
        }else {//等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }        
    }
}

class Producer extends Thread{//生产者
    private Clerk clerk;

    public Producer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":开始消费产品...");
        
        while (true){//想看交替打印的可以在这加Thread.sleep()。
            // 生产者刚释放锁,又大概率被生产者抢到了!!!
            clerk.AddCount();
        }       
    }
}

class Consumer extends Thread{//消费者
    private Clerk clerk;

    public Consumer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":开始生产产品...");

        while (true){
            clerk.SubCount();
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值