重温java知识(三十九、JUC并发编程之七:阻塞队列之三:延迟队列)

在JUC中提供自动弹出数据的延迟队列DelayQueue,该类属于BlockingQueue接口子类,而对于延迟操作的计算则需要通过Delayed接口进行计算。

1、使用延迟队列(模拟讨论会一次离开的场景)的例子:

package com.mydemo;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class JUCDemo {

    public static void main(String[] args) throws InterruptedException {

        // 定义延迟队列
        BlockingQueue<Student> blockingQueue = new DelayQueue<>();

        // 保存队列延迟信息
        blockingQueue.put(new Student("小明", 2, TimeUnit.SECONDS));
        blockingQueue.put(new Student("小华", 5, TimeUnit.SECONDS));
        blockingQueue.put(new Student("小红", 10, TimeUnit.SECONDS));

        // 是否还有人在
        while (!blockingQueue.isEmpty()){
            // 获取弹出数据
            Student student = blockingQueue.take();
            System.out.println(student);
            // 延迟操作
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

// 定义延迟计算
class Student implements Delayed {

    private String name;        // 姓名
    private long delay;         // 停留时间
    private long expire;        // 离开时间


    public Student(String name, long delay, TimeUnit timeUnit) {
        this.name = name;
        // 失效时间计算
        // 如果要计算离开时间,肯定需要与当前系统时间进行比较,系统时间返回的都是毫秒
        this.delay = TimeUnit.MILLISECONDS.convert(delay, timeUnit);
        this.expire = System.currentTimeMillis() + this.delay;
    }

    @Override
    public String toString() {
        return this.name + "同学已经到了预计的停留时间“"
                + TimeUnit.SECONDS.convert(this.delay, TimeUnit.MILLISECONDS)
                + "”秒,已经离开了。";
    }

    /**
     * 延迟时间计算
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    /**
     * 队列弹出计算
     * @param o
     * @return
     */
    @Override
    public int compareTo(Delayed o) {
        return (int)(this.delay - this.getDelay((TimeUnit.MILLISECONDS)));
    }
}

运行结果:
小明同学已经到了预计的停留时间“2”秒,已经离开了。
小华同学已经到了预计的停留时间“5”秒,已经离开了。
小红同学已经到了预计的停留时间“10”秒,已经离开了。

2、实现缓存操作的例子:

package com.mydemo;

import java.util.Map;
import java.util.concurrent.*;

public class JUCDemo {

    public static void main(String[] args) throws Exception {

        // 定义缓存类对象
        Cache<Long, News> cache = new Cache<>();

        // 向缓存保存数据
        cache.put(1l, new News(1L, "新闻标题1"));
        cache.put(2l, new News(2L, "新闻标题2"));
        cache.put(3l, new News(3L, "新闻标题3"));

        // 通过缓存获取数据
        System.out.println("缓存数据1l : " + cache.get(1l));
        System.out.println("缓存数据2l : " + cache.get(2l));
        System.out.println("缓存数据3l : " + cache.get(3l));

        // 延迟获取---设置的是2秒自动删除,所以5秒后没数据了
        TimeUnit.SECONDS.sleep(5);

        System.out.println("==============================");

        // 通过缓存获取数据
        System.out.println("缓存数据3l : " + cache.get(3l));

    }
}

// 定义一个缓存数据处理类
class Cache<K, V>{

    private static final TimeUnit TIME = TimeUnit.SECONDS;          // 时间工具类
    private static final long DELAY_SECONDES = 2;                   // 缓存时间
    private Map<K, V> cacheObjects = new ConcurrentHashMap<>();     // 设置缓存集合

    // 启动守护线程
    private BlockingQueue<DelayedItem<Pair>> blockingQueue = new DelayQueue<>();

    
    /**
     * 无参构造
     */
    public Cache() {
        Thread thread = new Thread(()->{
            while (true){
                try {
                    // 数据消费
                    DelayedItem<Pair> delayedItem = Cache.this.blockingQueue.take();
                    // 有数据
                    if(delayedItem != null){
                        // 获取数据
                        Pair pair = delayedItem.getItem();

                        // 删除数据
                        Cache.this.cacheObjects.remove(pair.key, pair.value);
                    }
                }catch (Exception e){}
            }
        });
        // 设置后台线程
        thread.setDaemon(true);
        // 线程启动
        thread.start();
    }

    /**
     * 保存数据
     * @param key
     * @param value
     */
    public void put(K key, V value) throws Exception {
        // 数据保存
        V oldValue = this.cacheObjects.put(key, value);

        // 重复保存
        if (oldValue != null) {
            // 删除已有的数据
            this.blockingQueue.remove(oldValue);
        }
        this.blockingQueue.put(new DelayedItem<Pair>(new Pair(key, value), DELAY_SECONDES, TIME));
    }

    /**
     * 获取缓存数据
     * @param key
     * @return
     */
    public V get(K key){
        // Map查询
        return this.cacheObjects.get(key);
    }

    // 封装保存数据
    private class Pair{
        private K key;      // 数据key
        private V value;    // 数据value

        /**
         * 双参构造函数---数据value
         * @param key
         * @param value
         */
        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }


    private class DelayedItem<T> implements Delayed {

        private T item;         // 数据项
        private long delay;     // 保存时间
        private long expire;    // 失效时间

        /**
         * 三参构造
         * @param item
         * @param delay
         * @param timeUnit
         */
        public DelayedItem(T item, long delay, TimeUnit timeUnit) {
            this.item = item;
            this.delay = TimeUnit.MILLISECONDS.convert(delay, timeUnit);
            this.expire = System.currentTimeMillis() + this.delay;
        }

        /**
         * 延时计算
         * @param unit
         * @return
         */
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            return (int)(this.delay - this.getDelay(TimeUnit.MILLISECONDS));
        }

        public T getItem() {
            return item;
        }

        public void setItem(T item) {
            this.item = item;
        }
    }
}

// 新闻数据
class News{
    private long nid;
    private String title;

    public News(long nid, String title) {
        this.nid = nid;
        this.title = title;
    }

    @Override
    public String toString() {
        return "News{" +
                "新闻编号:" + this.nid +
                ", 新闻标题:" + this.title + '\'' +
                '}';
    }
}

运行结果:
缓存数据1l : News{新闻编号:1, 新闻标题:新闻标题1'}
缓存数据2l : News{新闻编号:2, 新闻标题:新闻标题2'}
缓存数据3l : News{新闻编号:3, 新闻标题:新闻标题3'}
==============================
缓存数据3l : null

你可能感兴趣的:(Java,java)