• 可阻塞队列的实现


    描述

    队列包含固定长度的队列和不固定长度的队列。那什么是可阻塞队列呢?阻塞队列的作用和实际应用在哪里呢?阻塞队列又是如何实现的呢?

    带着这几个问题我们就来详细了解一下阻塞队列吧!

    想要用队列来实现可阻塞的队列,我们首先应该了解一下BlockingQueue这个接口。查看BlockingQueue帮助文档发现,有各个方法的区别对比的表格(见下表)。发现只有put和take方法才具有阻塞效果。

      Throws exception Special value Blocks Times out
    Insert add(e) offer(e) put(e) offer(e, time, unit)
    Remove remove() poll() take() poll(time, unit)
    Examine element() peek() not applicable not applicable

    可阻塞的队列我想应该不用多解释了,阻塞队列可以应用于线程之间的切换运行,也可以用于数据的共享与同步等。阻塞队列的实现方法在下面的Example中介绍的很详细,可以将代码实际运行之后分析结果来学习。

    Example

    下面我将使用 具有3个空间的队列来演示阻塞队列的功能和效果。

    示例代码:

    public class BlockingQueueTest {
        public static void main(String[] args) {
            final BlockingQueue queue = new ArrayBlockingQueue(3);
            for(int i=0;i<2;i++){
                new Thread(){
                    public void run(){
                        while(true){
                            try {
                                Thread.sleep((long)(Math.random()*1000));
                                System.out.println(Thread.currentThread().getName() + "准备放数据!");                            
                                queue.put(1);
                                System.out.println(Thread.currentThread().getName() + "已经放了数据," +                             
                                            "队列目前有" + queue.size() + "个数据");
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    
                }.start();
            }
            
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            //将此处的睡眠时间分别改为100和1000,观察运行结果
                            Thread.sleep(1000);
                            System.out.println(Thread.currentThread().getName() + "准备取数据!");
                            queue.take();
                            System.out.println(Thread.currentThread().getName() + "已经取走数据," +                             
                                    "队列目前有" + queue.size() + "个数据");                    
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();            
        }
    }

    接下来我将使用 两个具有1个空间的队列来实现同步通知的功能。

    我们先创建两个具有1个空间的队列queue1和queue2,在匿名构造方法中为queue2先执行put()方法放入一个数据。此时执行到queue2的put()方法会被阻塞,而此时queue1可以执行put()方法,put()方法完成后调用queue2的take()方法取走数据,所以queue2的put()方法就可以执行了,queue2执行完成后,再调用queue1的take()方法。如此就能实现我们的要求了!

    示例代码:

    public class BlockingQueueCommunication {
    
        public static void main(String[] args) {
            final Business business = new Business();
            new Thread(
                    new Runnable(){
                            public void run(){
                                for(int i=1;i<=50;i++){
                                    business.sub(i);
                                }
                            }
                        }
                    ).start();
    
            for(int i=1;i<=50;i++){
                business.main(i);
            }
        }
    
        static class Business {
            BlockingQueue<Integer> queue1 = new ArrayBlockingQueue<Integer>(1);
            BlockingQueue<Integer> queue2 = new ArrayBlockingQueue<Integer>(1);
            //匿名构造方法,只会在创建类的实例时执行一次
            {
                try {
                    queue2.put(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
            public void sub(int i){
                    try {
                        queue1.put(1);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    for(int j=1;j<=10;j++){
                        System.out.println("sub thread sequece of " + j + ",loop of " + i);
                    }
                    try {
                        queue2.take();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
            
            public void main(int i){
                    try {
                        queue2.put(1);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    for(int j=1;j<=100;j++){
                        System.out.println("main thread sequece of " + j + ",loop of " + i);
                    }
                    try {
                        queue1.take();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }
    }

     阻塞队列与Semaphore有些相似,但也不同。阻塞队列是一方存放数据,另一方释放数据,Semaphore通常则是由同一方设置和释放信号量。

  • 相关阅读:
    Adobe Acrobat XI pro v11.0.10中文版
    微软Office 2019 批量授权版21年04月更新版【福利】
    如何在PS里把证件照调正
    PS2020如何把图片中模糊不清的文字变清晰
    Office有效序列号大全
    计量经济学软件EViews11正式版【附激活文件】
    处理v-html的潜在XSS风险
    for 和 forEach 使用return,是跳出当前的循环,还是整个循环
    VUE防止多次点击,重复请求
    vue 分页插件使用
  • 原文地址:https://www.cnblogs.com/shen-smile/p/5146589.html
Copyright © 2020-2023  润新知