前言
最近碰到一个场景,在开发一个需求的过程中将系统的接口封装了一层,但是系统接口全部是以异步的形式回调的,这导致两个问题:
- 外部操作传入封装类的时候,上一次的操作还未完成,导致封装内部对象状态并不正确
- 某些场景下外部操作会并发地创建,因此需要一个队列来完成有序执行和生产者阻塞
基于以上两点,需要实现一个简易的队列,满足开发中的需要
过程分析
首先需要创建一个队列,用来保存 Runnable
任务,在这里选择的是 LinkedBlockingQueue
队列,当然也可以使用 ArrayBlockingQueue
队列限制任务数,或者在 SimpleAsyncToSyncQueue
内部自己实现
SimpleAsyncToSyncQueue
本身作为任务分配者,单独运行在一个线程内,此时生产者可能在不同线程中同时向 LinkedBlockingQueue
传入任务,这部分存在多线程操作的情况,好在 LinkedBlockingQueue
内部已经实现
因为生产者或消费者可能处于不同的线程中,因此实际控制的逻辑均放在 SimpleAsyncToSyncQueue
中,此处用到的是 Java 提供的线程锁工具 LockSupport
,在运行了 Runnable
之后,SimpleAsyncToSyncQueue
会调用 LockSupport.park()
将自身线程锁定,等待任务完成
Runnable
运行完成并不一定是任务完成,真正的任务可能在多个调用链之后才结束,因此在任务的调用链中无论是正常结束、非法值返回又或者抛出异常,都需要调用 unlock()
方法解锁SimpleAsyncToSyncQueue
线程
结论
package xyz.slkagura.thread;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.LockSupport;
public class SimpleAsyncToSyncQueue {
private static final String SIMPLE_ASYNC_TO_SYNC_QUEUE_TAG = SimpleAsyncToSyncQueue.class.getSimpleName();
private final LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<>();
private final Thread mThread = new Thread(this::run);
private final Handler mHandler = new Handler(Looper.getMainLooper());
private boolean mIsAuto = false;
public void start() {
if (!mThread.isAlive()) {
mThread.start();
}
}
public void stop() {
if (mThread.isAlive() && !mThread.isInterrupted()) {
mThread.interrupt();
}
}
public void setAuto(boolean isAuto) {
mIsAuto = isAuto;
}
private void run() {
try {
if (mIsAuto) {
mQueue.take().run();
}
while (!mThread.isInterrupted()) {
LockSupport.park();
Runnable runnable = mQueue.take();
runnable.run();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void offer(@NonNull Runnable runnable, boolean isMain) {
if (isMain) {
mQueue.offer(() -> {
mHandler.post(runnable);
});
} else {
mQueue.offer(runnable);
}
}
public void offer(@NonNull Runnable runnable) {
offer(runnable, false);
}
public void unlock() {
LockSupport.unpark(mThread);
}
public static void test() {
SimpleAsyncToSyncQueue consumer = new SimpleAsyncToSyncQueue();
consumer.setAuto(true);
consumer.start();
for (int i = 0; i < 100; i++) {
final int id = i;
boolean isSync = Math.random() < 0.9D;
String groupId = isSync ? "group-1" : "group-2";
consumer.offer(() -> {
Log.d(SIMPLE_ASYNC_TO_SYNC_QUEUE_TAG, "task: ", id, " group: ", groupId, " sync: ", String.valueOf(isSync), " start: ", System.nanoTime());
new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
consumer.unlock();
Log.d(SIMPLE_ASYNC_TO_SYNC_QUEUE_TAG, "task: ", id, " group: ", groupId, " sync: ", String.valueOf(isSync), " unlock: ", System.nanoTime());
}).start();
Log.d(SIMPLE_ASYNC_TO_SYNC_QUEUE_TAG, "task: ", id, " group: ", groupId, " sync: ", String.valueOf(isSync), " end: ", System.nanoTime());
});
}
}
}
标签:异步,runnable,队列,简陋,void,new,mThread,public,SimpleAsyncToSyncQueue
From: https://www.cnblogs.com/slkagura/p/16971154.html