我做了一个简单的TaskManager
尝试管理项目所需的Runnable
队列。但是,在一个简单的场景中,添加新的Runnable
会阻塞调用线程(主UI线程)。
在当前任务未完成时添加新任务时会发生这种情况。 您可以在下面找到重现它的方案。 我不清楚为什么,以及如何防止这种情况。
这是任务管理器类:
public class TaskManager {
private Queue<Runnable> executionQueue;
private final Object lock = new Object();
public TaskManager() {
executionQueue = new LinkedList<>();
startListening();
}
public void executeAsyncWithCompl(Runnable runnable, CompletionHandler completionHandler) {
Runnable runnableWithCompl = new RunnableWithCompl(runnable, completionHandler);
executeRunnable(runnableWithCompl);
}
private void executeRunnable(Runnable runnable) {
synchronized (lock) {
executionQueue.add(runnable);
lock.notifyAll();
}
}
public void release() {
synchronized (lock) {
lock.notify();
}
}
private void startListening() {
Thread executionThread = new Thread(new Runnable() {
@Override
public void run() {
listenTasks();
}
});
executionThread.start();
}
private void listenTasks() {
synchronized (lock) {
while (true) {
try {
if(executionQueue.isEmpty()) {
lock.wait();
}
Runnable runnable = executionQueue.poll();
runnable.run();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
}
这是RunnableWithCompl类:
public class RunnableWithCompl implements Runnable {
private CompletionHandler completionHandler;
private Runnable runnable;
public RunnableWithCompl(Runnable runnable, CompletionHandler completionHandler) {
this.runnable = runnable;
this.completionHandler = completionHandler;
}
@Override
public void run() {
runnable.run();
if(completionHandler != null)
completionHandler.onFinish();
}
}
和CompletionHandler接口:
public interface CompletionHandler {
void onFinish();
}
场景。假设您有一个带有微调器的Activity(用于显示UI未被阻止),以及一个用于触发长任务的按钮。
private TaskManager taskManager;
public void init() {
taskManager = new TaskManager();
launchLongTask();
}
private void onButtonClick() {
launchLongTask() ;
}
private void launchLongTask() {
Runnable longTask = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Log.d(TAG, "Launching long task");
taskManager.executeAsyncWithCompl(longTask, new CompletionHandler() {
@Override
public void onFinish() {
Log.d(TAG, "Long task finished");
}
});
}
答案 0 :(得分:1)
问题出在您的startListening()
实施中。
它在执行任务时将监视器保持到lock
,这意味着在执行工作时没有其他方法可以获取监视器。
这意味着release()
和executeRunnable(...)
将会阻止,直到没有其他可运行的队列排队。
这也意味着如果在其他线程之前通知运行startListening()
的线程,线程可能会阻塞,因为这意味着这些线程在释放监视器之前无法继续。