내 프로젝트에 필요한 Runnable
큐를 관리하려고 간단한 TaskManager
을 만들었습니다. 그러나 간단한 시나리오에서 새로운 Runnable
을 추가하면 호출 스레드 (기본 UI 스레드)가 차단됩니다.동기화, 잠금 및 대기 메인 UI 스레드
현재 작업이 완료되지 않은 상태에서 새 작업을 추가하면 이런 일이 발생합니다. 아래에서 재생산 시나리오를 볼 수 있습니다. 이유를 분명히 이해하지 못하고 어떻게 예방할 수 있습니까?
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 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 interface CompletionHandler {
void onFinish();
}
시나리오
이
는 작업 관리자 클래스입니다. 회 전자 (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");
}
});
}
당신은'java.util.concurrent'에서 Executor 클래스의 바퀴를 재발 명하고있는 것처럼 보입니다 –