线程(生产者消费者模式+阻塞队列)

目录

线程的等待和通知

Object类中关于线程的方法

同步方法案例:

同步锁案例:

wait()和sleep()的区别

生产者消费者模式

阻塞队列


 

线程的等待和通知

Object类中关于线程的方法

  • wait() 让当前线程进入等待状态,直到被通知为止

  • wait(long) 让当前线程进入等待状态,同时设置时间;直到被通知为止或时间结束

  • notify() 随机通知一个等待线程

  • notifyAll() 通知所有的等待线程

 注意:等待和通知方法必须是锁对象,否则会抛出IllegalMonitorStateException

同步方法案例:

/**
 * 通过锁对象将线程等待,经过5秒通知该线程来执行
 */
public class WaitDemo {

    public synchronized void print() throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "--->" +i);
            if(i == 50){
                //让当前线程等待
                this.wait();
            }
        }
    }

    public synchronized void notifyTest(){
        //让等待的线程执行
        this.notifyAll();
    }

    public static void main(String[] args) {
        WaitDemo waitDemo = new WaitDemo();
        new Thread(()->{
            try {
                waitDemo.print();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        waitDemo.notifyTest();
    }
}

同步锁案例:

public class WaitDemo {
    Lock lock=new ReentrantLock();
    Condition condition=lock.newCondition();
    public void print() throws InterruptedException {
        lock.lock();
        try {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+i);
                if(i==50){
                    condition.await();
                }
            }
        }finally {
            lock.unlock();
        }
    }
    public void lockTest(){
        lock.lock();
        try {
            condition.signal();
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {

        WaitDemo waitDemo = new WaitDemo();
        new Thread(()->{
            try {
                waitDemo.print();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        waitDemo.lockTest();
    }
}

wait()和sleep()的区别

  1. 调用对象不同

    wait() 由锁对象调用

    sleep() 由线程调用

  2. 锁使用不同

    执行wait后,自动释放锁

    执行sleep后,不会释放锁

  3. 唤醒机制不同

    执行wait后,可以被通知唤醒

    执行sleep后,只能等待时间结束后,自动唤醒

生产者消费者模式

生产者消费者模式 是Controlnet网络中特有的一种传输数据的模式,设置方便,使用安全快捷。

 一种设计模式,不属于GOF23

生产者和消费者

  • 生产者

    产生数据的模块就属于生产者

  • 消费者

    处理数据的模块就属于消费者

生产者和消费者之间的问题

  • 耦合性高,生产者和消费者联系紧密,不利于系统的扩展和维护

  • 并发性能低,同时能处理请求量少

  • 忙闲不均,生产者和消费者的速度不一致,带来系统资源的浪费

实现过程:

  1. 通过添加缓冲区,设置上限

  2. 生产者生产数据,向缓冲区存放,如果满了,生产者进入等待,直到缓冲区有空的位置通知生产者生产;

  3. 消费者从缓冲区取数据进行消费,如果空了,消费者进入等待,直到缓冲区有数据再通知消费者消费

解决问题:

  • 解耦

  • 提高并发性能

  • 解决忙闲不均

/**
 * 包子铺
 */
public class BaoziShop {
    /**
     * 包子
     */
    class Baozi{
        private int id;
        public Baozi(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "包子--" + id;
        }
    }
    //上限
    public static final int MAX_COUNT = 100;
    //缓冲区 存放数据
    private List<Baozi> baozis = new ArrayList<>();

    /**
     * 做包子
     */
    public synchronized void makeBaozi() throws InterruptedException {
        //判断缓冲区是否满了
        if(baozis.size() == MAX_COUNT){
            System.out.printf("缓冲区满了,%s等待%n",Thread.currentThread().getName());
            //让生产者线程等待
            this.wait();
        }else{
            //通知生产者线程生产
            this.notifyAll();
        }
        //创建包子
        Baozi baozi = new Baozi(baozis.size() + 1);
        System.out.println(Thread.currentThread().getName()+"做了"+baozi);
        //保存到缓冲区
        baozis.add(baozi);
    }

    /**
     * 拿包子
     */
    public synchronized void takeBaozi() throws InterruptedException {
        //判断缓冲区是否空了
        if(baozis.size() == 0){
            System.out.printf("缓冲区空了,%s等待%n", Thread.currentThread().getName());
            //让消费者等待
            this.wait();
        }else{
            //通知消费者消费
            this.notifyAll();
        }
        //获得第一个包子,并删除
        if(baozis.size() > 0){
            Baozi baozi = baozis.remove(0);
            System.out.println(Thread.currentThread().getName()+"吃了"+baozi);
        }
    }

    public static void main(String[] args) {
        BaoziShop baoziShop = new BaoziShop();
        //一个生产者
        Thread productor = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    baoziShop.makeBaozi();
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        productor.start();
        //10个消费者吃10个包子
        for (int i = 0; i < 10; i++) {
            Thread consumer = new Thread(() ->{
                try {
                    for (int j = 0; j < 10; j++) {
                        baoziShop.takeBaozi();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            consumer.start();
        }
    }
}

应用场景:

  • 12306售票

  • 消息队列

  • 线程池

  • 等等

阻塞队列

应用了生产者消费者模式的集合,能够根据数据满或空的情况,自动对线程执行等待和通知

BlockingQueue 接口

  • put 添加数据,达到上限会自动让线程等待

  • take 取并删除数据,数据空了会自动让线程等待

实现类

ArrayBlockingQueue 类 数据结构为数组

LinkedBlockingQueue类 链表结构

public class BaoziShop2 {

     static class Baozi{
         private int id;
         public Baozi(int id){
             this.id=id;
         }
         @Override
         public String toString() {
             return "包子---" +id;
         }
     }


    public static void main(String[] args) {
        BlockingQueue<Baozi> baozis = new ArrayBlockingQueue<Baozi>(100);
        new Thread(()->{
             for (int i = 0; i < 100; i++) {
                 try {
                     Baozi baozi = new Baozi(baozis.size() + 1);
                     baozis.put(baozi);
                     System.out.println(Thread.currentThread().getName()+"生产了"+baozi);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }).start();
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                for (int j = 0; j < 20; j++) {
                    try {
                        Baozi take = baozis.take();
                        System.out.println(Thread.currentThread().getName()+"吃了"+take);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值