Java——生产者与消费者模型

目录

1.wait( )

2.notify()

3.线程阻塞的常见情况

4.monitor的两个队列

5.生产者与消费者模型

5.1 单生产、单消费

5.2 多生产、多消费


1.wait( )

使线程停止运行,会释放对象锁。

  • 特点
  1. wait()使当前线程调用该方法后进行等待,并且将该线程置入锁对象的等待队列中,直到接到通知或被中断为止。
  2. wait()只能在同步方法 / 同步代码块中调用,如果调用wait()时,没有适当的锁,会抛出异常。
  3. wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁。
  • wait()之后的线程继续执行有两种方法:
  1. 调用该对象的notify()唤醒等待线程
  2. 线程等待是调用interrupt()中断该线程

/**
 * wait()
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) {
        MyThread mt=new MyThread();
        Thread thread=new Thread(mt);
        thread.start();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }
}

class MyThread implements Runnable{
    private Object object=new Object();

    @Override
    public void run() {
        synchronized (object){
            System.out.println("wait()开始");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("wait()结束");
        }
    }
}
  • wait(long time):如果到了预计时间还未被唤醒,线程将继续执行
/**
 * wait(long time)
 * Author: qqy
 */
public class Test1 {
    public static void main(String[] args) {
        MyThread mt=new MyThread();
        Thread thread=new Thread(mt);
        thread.start();
    }
}

class MyThread implements Runnable{
    private Object object=new Object();

    @Override
    public void run() {
        synchronized (object){
            System.out.println("wait()开始");
            try {
                //等1s后,结束
                object.wait(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("wait()结束");
        }
    }
}

2.notify()

使停止的线程继续运行。

  • 特点
  1. notify()必须在同步方法 / 同步代码块中调用,用来唤醒等待在该对象上的线程。如果有多个线程等待,则任意挑选一个线程唤醒。
  2. notify()执行后,唤醒线程不会立刻释放对象锁,等待唤醒线程全部执行完毕后才释放对象锁。
  • notifyAll():唤醒所有在该对象上等待的线程。
/**
 * notify()
 * Author: qqy
 */
public class Test2 {
    public static void main(String[] args) {
        Object object=new Object();
        MyThread1 myThread1=new MyThread1(object,true);
        MyThread1 myThread2=new MyThread1(object,false);
        Thread waitThread=new Thread(myThread1,"等待线程");
        Thread notifyThread=new Thread(myThread2,"唤醒线程");
        waitThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyThread.start();
    }
}

class MyThread1 implements Runnable{
    //锁定对象
    private Object object;
    //决定等待or唤醒
    private boolean flag;

    public MyThread1(Object object, boolean flag) {
        this.object = object;
        this.flag = flag;
    }

    //等待方法
    public void waitMethod(){
        synchronized (object){
            System.out.println(Thread.currentThread().getName()+"   wait()开始");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"   wait()结束");
        }
    }

    //唤醒方法
    public void notifyMethod(){
        synchronized (object){
            System.out.println(Thread.currentThread().getName()+"   notify()开始");
            object.notify();
            System.out.println(Thread.currentThread().getName()+"   notify()结束");
        }
    }
    @Override
    public void run() {
        if(flag){
            waitMethod();
        }else {
            notifyMethod();
        }
    }
}

3.线程阻塞的常见情况

  1. 调用sleep( ),主动放弃占有的cpu,不会释放对象锁
  2. 调用阻塞式 I/O 方法(read()、write()),在该方法返回前,线程阻塞
  3. 线程试图获取一个monitor,但该monitor被其他线程所持有导致阻塞
  4. 线程等待某个通知,即调用wait(),释放对象锁
  5. 调用线程suspend(),将线程挂起,容易导致死锁,已弃用。

4.monitor的两个队列

每一个monitor都有两个队列——同步队列、等待队列

  • 同步队列:存放因为竞争monitor失败导致阻塞的线程,这些线程等待cpu调度再次竞争锁。

  • 等待队列:存放因为调用wait()导致线程等待的线程,唤醒后进入同步队列竞争锁。

5.生产者与消费者模型

  • 5.1 单生产、单消费

/**
 * 生产者与消费者模型——单生产、单消费
 * Author: qqy
 */
public class Test3 {
    public static void main(String[] args) {
        Goods1 goods1=new Goods1();
        Thread produceThread=new Thread(new Producer1(goods1),"生产者");
        Thread customThread=new Thread(new Customer1(goods1),"消费者");
        produceThread.start();
        customThread.start();
    }
}

//商品类
class Goods1{
    private String goodsName;
    private int count;

    //生产商品方法
    public synchronized void set(String goodsName){
        if(count>0){
            System.out.println("库存充足,稍等一会儿");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.goodsName=goodsName;
        this.count++;
        System.out.println(Thread.currentThread().getName()+"生产"+toString());
        notify();
    }

    //消费商品方法
    public synchronized void get(){
        if(count==0){
            System.out.println("无商品,稍等片刻");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.count--;
        System.out.println(Thread.currentThread().getName()+"消费"+toString());
        notify();
    }

    //toString
    @Override
    public String toString() {
        return "Goods{" +
                "goodsName='" + goodsName + '\'' +
                ", count=" + count +
                '}';
    }
}

//消费者线程
class Customer1 implements Runnable{
    private Goods1 goods;

    public Customer1(Goods1 goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        goods.get();
    }
}

//生产者线程
class Producer1 implements Runnable{
    private Goods1 goods;

    public Producer1(Goods1 goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        goods.set("YSL");
    }
}
  • 5.2 多生产、多消费

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 生产者消费者模型——多生产、多消费
 * Author: qqy
 */
public class Test {
    public static void main(String[] args) {
        Queue<Goods> goods=new LinkedList<>();
        //标记商品
        AtomicInteger name=new AtomicInteger(1);
        Object monitor=new Object();

        //两个生产者
        Producer producer=new Producer(goods,monitor,name);
        Producer producer1=new Producer(goods,monitor,name);
        //两个消费者
        Customer customer=new Customer(goods,monitor);
        Customer customer1=new Customer(goods,monitor);

        new Thread(producer,"生产者1").start();
        new Thread(producer1,"生产者2").start();
        new Thread(customer,"消费者1").start();
        new Thread(customer1,"消费者2").start();
    }
}

class Goods{
    private String name;

    public Goods(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Goods{" +
                "name='" + name + '\'' +
                '}';
    }
}

//生产者
class Producer implements Runnable{
    private final Queue<Goods> goods;

    private final Object monitor;

    private final AtomicInteger atomicInteger;

    Producer(Queue<Goods> goods, Object monitor, AtomicInteger atomicInteger) {
        this.goods = goods;
        this.monitor = monitor;
        this.atomicInteger = atomicInteger;
    }


    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (monitor) {
                //商品池满了
                if (this.goods.size() == 10) {
                    try {
                        //等待,直到通知没有商品了
                        this.monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    Goods goods=new Goods(String.valueOf(atomicInteger.getAndAdd(1)));
                    //将生产的商品加入队列
                    this.goods.add(goods);
                    //打印生产商品信息
                    System.out.println(Thread.currentThread().getName()+"  生产"+goods);
                }
            }
        }
    }
}

//消费者
class Customer implements Runnable{
    private final Queue<Goods> goods;

    private final Object monitor;

    Customer(Queue<Goods> goods, Object monitor) {
        this.goods = goods;
        this.monitor = monitor;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (monitor){
                //商品为空,通知所有生产者
                if(this.goods.isEmpty()){
                    this.monitor.notifyAll();
                }else{
                    //消费商品
                    Goods goods=this.goods.poll();
                    //打印消费信息
                    System.out.println(Thread.currentThread().getName()+"  消费"+goods);
                }
            }
        }
    }
}

  • sleep()与wait()的区别:

1. sleep()是Thread类中定义的方法,到了一定的时间后该线程自动唤醒,不会释放对象锁。

2. wait()是Object类中定义的方法,要想唤醒必须使用notify()、notifyAll()方法才能唤醒,会释放对象锁 

猜你喜欢

转载自blog.csdn.net/qq_42142477/article/details/86411587