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

队列:先进先出

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,不固定大小队列

原文地址:https://www.cnblogs.com/zjxiang/p/9452262.html