JUC 并发编程--09, 阻塞队列: DelayQueue, PriorityBlockingQueue ,SynchronousQueue, 定时任务线程池: ScheduledThreadPoolExecutor

先看DelayQueue 这个是用优先级队列实现的无界限的延迟队列,直接上代码:

/**
 * 这个是 {@link DelayQueue} 延时队列 的验证使用类
 */
class MyDelayed implements Delayed {
    private long delayTime;//该任务在队列中的延迟时间
    private long expire;//这个时间: 表示过时时间+当前时间,  到期时间
    private String taskName;//任务名字

    @Override
    public String toString() {
        return "MyDelayed{" +
                "delayTime=" + delayTime +
                ", expire=" + expire +
                ", taskName='" + taskName + '\'' +
                '}';
    }

    public MyDelayed(long delayTime, String taskName) {
        this.delayTime = delayTime;
        this.taskName = taskName;
        this.expire = System.currentTimeMillis() + delayTime;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        // 这个方法是 定义了 剩余到期时间
        //unit.convert(), 这个方法是转换, 将数值转换为毫秒,  将延时时间转换为毫秒
        return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        // 这里设置比较规则,从小到大
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        // 从大到小
        //return (int) ( o.getDelay(TimeUnit.MILLISECONDS) - this.getDelay(TimeUnit.MILLISECONDS));
    }

    public static void main(String[] args) throws InterruptedException {
        boolean flag = true;
        /**
         * 延迟队列: 这是一个无界队列,添加元素时候不阻塞, 每个任务里面都有一个延迟时间,
         * 超过这个时间,才将任务取出来,且这个队列中放的元素,只能是 MyDelayed,(实现了Delayed)
         */
        DelayQueue<MyDelayed> delayQueue = new DelayQueue<>();
        Random random = new Random();
        for (int i = 0; i < 20; i++) {
            MyDelayed myDelayed = new MyDelayed(random.nextInt(500), "任务" + i);
            delayQueue.put(myDelayed);
        }
        while (flag) {
            // 这里使用 take(). 阻塞获取的方法,当获取不到的时候,会阻塞,直到延时时间到期,获取到为止
            //还有一个 获取方法: poll(). 点进源码看到: 延时时间没到,获取结果为null, 当延时时间到了之后,才会获取到结果
            MyDelayed take = delayQueue.take();
            System.out.println(take);
            if (delayQueue.size() == 0) {
                flag = false;
            }
        }
    }
}

运行结果:

PriorityBlockingQueue, 这个队列,是支持优先级排序的 无界队列, 代码演示:

public class PriorityBlockingQueueDemo {
    /**
     * PriorityBlockingQueue; 无界队列, 添加元素的时候不阻塞
     * <p>
     * 这个队列是基于优先级的阻塞队列, 且只会阻塞消费者,不会阻塞生成者,所以在使用的时候,不能让生成的速度大于消费的速度,否则时间一长,会造成堆空间溢出({@link OutOfMemoryError})
     */
    public static void main(String[] args) throws InterruptedException {
        boolean flag = true;
        // PriorityBlockingQueue 队列中的元素 如果是基本数据类型,默认排序时从小到大, 如果是对象,可以实现Comparable接口来指定排序规则
        //PriorityBlockingQueue<String> priorityBlockingQueue = new PriorityBlockingQueue();
        PriorityBlockingQueue<MyTask> priorityBlockingQueue = new PriorityBlockingQueue();
        Random random = new Random();
        for (int i = 0; i < 20; i++) {
            //priorityBlockingQueue.put("任务"+i);
            priorityBlockingQueue.put(new MyTask("任务" + i, random.nextInt(100)));
        }
        while (flag) {
            //String take  = priorityBlockingQueue.take();
            MyTask take = priorityBlockingQueue.take();
            System.out.println(take);
            if (priorityBlockingQueue.size() == 0) {
                flag = false;
            }
        }
    }
}

class MyTask implements Comparable<MyTask> {
    private String taskName;
    private int age;

    public MyTask(String taskName, int age) {
        this.taskName = taskName;
        this.age = age;
    }

    @Override
    public String toString() {
        return "MyTask{" +
                "taskName='" + taskName + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(MyTask o) {
        return o.age - this.age;
    }
}

运行结果为: 可以看到是按照顺序来取出来的

SynchronousQueue, 这个队列是 不存储元素的队列,(传球手), 用这个队列来实现一个 生产者,消费者, 生产一个,消费一个, 代码如下:

class SynchronousQueueDemo {
    private static volatile boolean flag = true;
    private static AtomicInteger atomicInteger = new AtomicInteger();
    private BlockingQueue blockingQueue;

    public SynchronousQueueDemo(BlockingQueue blockingQueue) {
        this.blockingQueue = blockingQueue;
        System.out.println(blockingQueue.getClass().getName());
    }
    // 生产者
    public void producer() throws InterruptedException {
        String data = "";
        while(flag){
            data = atomicInteger.getAndIncrement()+"";//这是产品
            TimeUnit.SECONDS.sleep(1);// 1秒生成一个产品
            boolean offer = blockingQueue.offer(data);
            if(offer){
                System.out.println(Thread.currentThread().getName() + "添加成功, 元素为:" + data+"--队列是否为空:"+blockingQueue.isEmpty());
            }else{
                System.out.println(Thread.currentThread().getName() + "添加失败");
            }
        }
    }

    // 消费者
    public void consumer() throws InterruptedException {
        while(flag){
            try {
                System.out.println("消费了一个产品:"+blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("------------------------------------------");
        }
    }
    // 停止方法
    public void stop(){
        this.flag = false;
    }


    public static void main(String[] args) throws InterruptedException {
        /**
         *  相当于一个传球手, 不存储元素的队列, 所以容量都为空
         *
         * SynchronousQueue 它是一个对于元素来说空了才能存入,存在才能取出的队列,只保留一个元素在queue里。
         * 但是用处在哪里?如果替换成其它queue,比如ArrayBlockingQueue,会使得哪些事情做不到?
         *
         * 首先,它也是blockingqueue的一个实现,内部采用的就是ArrayBlockingQueue的阻塞原语,所以在功能上完全可以用ArrayBlockingQueue替换之,
         * 但是SynchronousQueue 是轻量级的,SynchronousQueue 不具有任何内部容量,甚至不具有一的容量,我们可以用来在线程间安全的交换单一元素。
         * 所以功能比较单一,优势应该就在于轻量吧~
         */
        SynchronousQueueDemo synchronousQueue = new SynchronousQueueDemo(new SynchronousQueue());

        SynchronousQueueDemo linkedTransferQueue = new SynchronousQueueDemo(new LinkedTransferQueue<String>());
        new Thread(()->{
            try {
                linkedTransferQueue.producer();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();


        new Thread(()->{
            try {
                linkedTransferQueue.consumer();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        TimeUnit.SECONDS.sleep(5);
        synchronousQueue.stop();
    }
}

运行结果:

关于定时任务线程池的分析

public static void main(String[] args) {
    /**
     * corePoolSize:4
     * maximumPoolSize: Integer.MAX_VALUE
     * keepAliveTime: 0
     * 单位: 微秒
     * 阻塞队列: DelayedWorkQueue
     * 线程工厂: Executors.defaultThreadFactory()
     * 拒绝策略: AbortPolicy,
     *
     */
    ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(4);
    /**
     *  这里引用别人博客:[https://www.cnblogs.com/txmfz/p/10338334.html]()
     *  定时任务线程池, 内部使用的队列是: DelayedWorkQueue, 用来定时从队列中取任务
     *
     *  这里不是直接使用的 DelayQueue(队列放的元素 只能是 Delayed类) ,是因为点进 DelayedWorkQueue源码可以看到内部维护了一个数组:RunnableScheduledFuture[]
     *  而 RunnableScheduledFuture 这个类最终是继承了 Delayed 类,
     *  他是DelayQueue的扩展, 是: 优先级队列实现+延迟队列实现  说明 DelayedWorkQueue的功能比 DelayQueue更强大,
     */
}
posted @ 2020-09-08 14:41  死不了好气呦  阅读(277)  评论(0编辑  收藏  举报