延迟阻塞队列的应用

x33g5p2x  于2022-03-22 转载在 其他  
字(2.4k)|赞(0)|评价(0)|浏览(281)

一 问题描述

3位游泳者同时进行游泳馆,各自游泳时间分别是 1 分钟,2 分钟,3 分钟,按规定到了结束时间后游泳者自动离开。请用队列模拟以上场景。

二 代码实现

1 游泳者类

package concurrent.swim;

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

/**
* @className: Swimmer
* @description: 游泳者
* @date: 2022/3/21
* @author: cakin
*/
public class Swimmer implements Delayed {
    // 姓名
    private String name;
    // 结束时间
    private long endTime;

    public Swimmer() {
    }

    public Swimmer(String name, long endTime) {
        this.name = name;
        this.endTime = endTime;
    }

    public String getName() {
        return this.name;
    }

    /*
       是否还有剩余时间。
       如果返回正数,表明还有剩余时间;
       如果返回0或者负数,说明已超时;超时时,才会让 DelayQueue 的 take() 方法真正取出元素。
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return endTime - System.currentTimeMillis();
    }

    // 线程(游泳者)之间,根据剩余时间的大小进行排序
    @Override
    public int compareTo(Delayed delayed) {
        Swimmer swimmer = (Swimmer) delayed;
        return this.getDelay(TimeUnit.SECONDS) - swimmer.getDelay(TimeUnit.SECONDS) > 0 ? 1 : 0;
    }
}

2 游泳池类

package concurrent.swim;

import java.util.concurrent.DelayQueue;

/**
* @className: Natatorium
* @description: 游泳馆
* @date: 2022/3/21
* @author: cakin
*/
public class Natatorium implements Runnable {
    // 用延迟队列模拟多个Swimmer,每个 Swimmer 的 getDelay() 方法就表示自己剩余的游泳时间
    private DelayQueue<Swimmer> queue = new DelayQueue<>();

    // 标识游泳馆是否开业
    private volatile boolean isOpen = true;

    /**
     * 功能描述:向 DelayQueue中 增加游泳者
     *
     * @param name     游泳者名字
     * @param playTime 游泳者时长
     * @author cakin
     * @date 2022/3/21
     */
    public void addSwimmer(String name, int playTime) {
        // 规定游泳的结束时间
        long endTime = System.currentTimeMillis() + playTime * 1000 * 60;
        Swimmer swimmer = new Swimmer(name, endTime);
        System.out.println(swimmer.getName() + "进入游泳馆,可供游泳时间:" + playTime + "分");
        this.queue.add(swimmer);
    }

    @Override
    public void run() {
        while (isOpen) {
            try {
                /*
                 * 注意:在 DelayQueue 中,take() 并不会立刻取出元素。
                 * 只有当元素(Swimmer)所重写的 getDelay() 返回0或者负数时,才会真正取出该元素。
                 */
                Swimmer swimmer = queue.take();
                System.out.println(swimmer.getName() + "游泳时间结束");
                // 如果 DelayQueue中 的元素已被取完,则停止线程
                if (queue.size() == 0) {
                    isOpen = false;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3 测试类

package concurrent.swim;

/**
* @className: TestNatatorium
* @description: 游泳馆测试类
* @date: 2022/3/21
* @author: cakin
*/
public class TestNatatorium {
    public static void main(String args[]) {
        try {
            Natatorium natatorium = new Natatorium();
            Thread nataThread = new Thread(natatorium);
            nataThread.start();
            natatorium.addSwimmer("zs", 1);
            natatorium.addSwimmer("ls", 2);
            natatorium.addSwimmer("ww", 3);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三 测试结果

zs进入游泳馆,可供游泳时间:1分

ls进入游泳馆,可供游泳时间:2分

ww进入游泳馆,可供游泳时间:3分

zs游泳时间结束

ls游泳时间结束

ww游泳时间结束

四 说明

该案例是用延迟阻塞队列解决问题,当 3 位游泳者时间结束时,就会陆续收到提示。

相关文章