DelayQueue 延时队列的使用

1. DelayQueue是什么

  DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。

2. DelayQueue能做什么

  2.1 订单业务:下单之后如果多少分钟之内没有付款就自动取消订单。

  2.2 任务超时处理。在网络协议请求应答交互时,处理超时未响应的请求等。

3. 示例展示

  3.1 创建 TimeOutQueue 类,使用 DelayQueue 队列

public class TimeOutQueue {
    private String TAG = getClass().getSimpleName();
    private String callbackIdKey = "callbackId";
    /**
     * 保存回调监听标识 callbackId
     */
    private Map<String, String> callBacks = new HashMap<>();
    /**
     * 保存一个延时检测的请求队列,元素超时的时候会被取出来
     * 保存需要进行超时检测的请求,这是一个延时的队列,元素超时的时候会被取出来
     */
    private DelayQueue<TimeOutItem> timeOutQueue = new DelayQueue<>();
    /**
     * 超时检测的线程管理器
     */
    private ExecutorService timeOutExecutor;

    /**
     * 超时检测线程
     */
    public void engineThread() {
        if (timeOutExecutor == null || timeOutExecutor.isShutdown()) {
            timeOutExecutor = Executors.newSingleThreadExecutor();
            timeOutExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        //Log.i(TAG, "timeOutQueue take()");
                        //只有超时的元素才会被取出来,没有的话会等待
                        TimeOutItem item = timeOutQueue.take();
                        if (item != null) {
                            String callBack = callBacks.remove(item.callbackId);
                            if (callBack != null) {
                                Log.i(TAG, callBack);
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //继续循环
                    if (timeOutExecutor != null && !timeOutExecutor.isShutdown()) {
                        run();
                    }
                    //Log.i(TAG, "timeOutExecutor stop");
                }
            });
        }
    }

    /**
     * 关闭线程
     */
    public void shutdownThread() {
        if (timeOutExecutor != null && !timeOutExecutor.isShutdown()) {
            //shutdown 和 shutdownNow 的主要区别是前者中断未执行的线程,后者中断所有的线程
            timeOutExecutor.shutdownNow();
            timeOutExecutor = null;
            //Log.i(TAG, "timeOutExecutor shutdownNow");
        }
    }

    /**
     * 添加回调Key
     *
     * @param callbackId
     */
    public void addCallback(String callbackId) {
        callBacks.put(callbackIdKey, callbackId);
        //放入延时队列 5秒
        long delayTime = 5 * 1000; //SECONDS MILLISECONDS
        timeOutQueue.add(new TimeOutItem(callbackIdKey, delayTime, TimeUnit.MILLISECONDS));
    }

    /**
     * 移除回调Key
     */
    public void removeCallBack() {
        //当完成任务时,可以及时移除 callBackKey
        callBacks.remove(callbackIdKey);
    }

    //延时队列的 item
    class TimeOutItem implements Delayed {
        String callbackId; //当前 callback 的 callbackId
        long executeTime;  //触发时间

        public TimeOutItem(String callbackId, long delayTime, TimeUnit timeUnit) {
            this.callbackId = callbackId;
            this.executeTime = System.currentTimeMillis() + (delayTime > 0 ? timeUnit.toMillis(delayTime) : 0);
            //Log.i(TAG, " executeTime: " + executeTime + " timeUnit: " + timeUnit.toMillis(delayTime));
        }

        //获取剩余时间
        //需要实现的接口,获得延迟时间   用过期时间-当前时间
        @Override
        public long getDelay(TimeUnit unit) {
            return executeTime - System.currentTimeMillis();
        }

        //比较延时,队列里元素的排序依据
        //用于延迟队列内部比较排序   当前时间的延迟时间 - 比较对象的延迟时间
        @Override
        public int compareTo(Delayed o) {
            long surplusTime = this.getDelay(TimeUnit.MILLISECONDS);
            long currentTime = o.getDelay(TimeUnit.MILLISECONDS);
            int compare = (int) (surplusTime - currentTime);
            //Log.i(TAG, " surplusTime: " + surplusTime + " currentTime: " + currentTime + " compare: " + compare);
            return compare;
        }
    }
}

  3.2 调用测试页布局,activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/but_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="64dp"
        android:minWidth="100dp"
        android:text="Add"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/but_remove"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="64dp"
        android:minWidth="100dp"
        android:text="Remove"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/but_add" />

    <Button
        android:id="@+id/but_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="64dp"
        android:minWidth="100dp"
        android:text="Stop"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/but_remove" />
</androidx.constraintlayout.widget.ConstraintLayout>

  3.3 调用测试页,MainActivity.java

public class MainActivity extends AppCompatActivity {
      private TimeOutQueue timeOutQueue;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          timeOutQueue = new TimeOutQueue();
          timeOutQueue.engineThread();
          initView();
      }
      //初始化View
      public void initView() {
          findViewById(R.id.but_add).setOnClickListener(v -> timeOutQueue.addCallback("callBackTest"));
          findViewById(R.id.but_remove).setOnClickListener(v -> timeOutQueue.removeCallBack());
          findViewById(R.id.but_stop).setOnClickListener(v -> timeOutQueue.shutdownThread());
      }
  }

4. 调用截图

猜你喜欢

转载自blog.csdn.net/u011193452/article/details/129669402