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());
}
}