• 线程应用:(九)阻塞队列的应用


    队列:先进先出

    1)ArrayBlockingQueue,固定大小队列

      当固定大小的队列满了时,可以选择以抛异常(Throws exception)、立马返回判断值(Special value)、阻塞(Blocks)中的1种形式进行操作。如下图。

      

    案例1:有2个线程从队列取数据,有1个线程往队列放数据。

    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ArrayBlockTest {
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
            final BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(3);
            
            for(int i=0;i<2;i++){        //有两个线程不停往队列里放数据
                final Integer data = i;
                service.execute(new Runnable() {
                    @Override
                    public void run() {
                        while(true){
                            try {
                                Thread.sleep((long)(Math.random()*1000));
                                System.out.println(Thread.currentThread().getName()+"准备放数据");
                                queue.put(data);    //队列如果满了,阻塞在这
                                System.out.println(Thread.currentThread().getName()+"已经放数据,目前队列数据数:"+queue.size());
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
            
            service.execute(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(1000);    //注释掉看看效果
                            System.out.println(Thread.currentThread().getName()+"准备取数据");
                            queue.take();    //取的快,阻塞在这
                            System.out.println(Thread.currentThread().getName()+"已经取数据,目前队列数据数:"+queue.size());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }

    案例2:原本使用单线程,要16秒才能完成打印日志,现在启动4个线程分别取打印,只要4秒即可完成。

    思路:主线程把任务放到队列里,然后让其他线程自己去取。

    //阻塞队列结合线程使用案例
    public class ArrayBlockTest2 {
        public static void main(String[] args) throws InterruptedException {
            final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16);
            
            //同时开启4个线程去打印,让原来1个线程要打印16s,现在只要打印4s
            for(int i=0;i<4;i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while(true){
                            try {
                                String log = queue.take();
                                parseLog(log);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
            }
            
            //主线程往队列放16个字符串
            for(int i=0;i<16;i++){
                final String log = ""+(i+1);
                queue.put(log);
            }
        }
        
        public static void parseLog(String log) throws InterruptedException{
            System.out.println(log+":"+(System.currentTimeMillis()/1000));
            Thread.sleep(1000);    //把打印时间设置为1s打印1次
        }
        
    }

    2)LinkedBlockingQueue,不固定大小队列

  • 相关阅读:
    IDEA中Spring Boot项目MyBaits提示Invalid bound statement (not found)错误
    js 算法 两个数组比较去重,性能优化
    window.open() 打开新标签,之前的sessionStorage还在
    自定义<el-table-column> 数据格式:数组对象,且每条对象中有一个数组对象
    VSCode 代码格式化 快捷键
    echarts的饼图label标签重叠解决办法
    vue打包 element-icons.woff 和element-icons.ttf 字体文件路径错误,导致icon图标显示成小方块的问题。
    vue中的$refs属性几个注意点
    js中的 || 与 && 运算符详解
    package.json与package-lock.json文件是干什么用的?
  • 原文地址:https://www.cnblogs.com/zjxiang/p/9452262.html
Copyright © 2020-2023  润新知