Java等待通知死锁问题
这是我的类,它连续执行依赖的Java等待通知死锁问题,java,multithreading,deadlock,wait,notify,Java,Multithreading,Deadlock,Wait,Notify,这是我的类,它连续执行依赖的Runnables。它所做的是并行执行所有的Runnable,但在完成时,等待队列中的头Runnable首先完成。头部完成后,第二项完成,依此类推 这段代码的问题是它会导致某种死锁。当执行多个任务时,它会停止执行。暂停调试器时,它显示所有线程都在等待wait()语句 /** * Executes all tasks in parallel, with completion handler called only when other tasks of same ke
Runnable
s。它所做的是并行执行所有的Runnable
,但在完成时,等待队列中的头Runnable
首先完成。头部完成后,第二项完成,依此类推
这段代码的问题是它会导致某种死锁。当执行多个任务时,它会停止执行。暂停调试器时,它显示所有线程都在等待wait()
语句
/**
* Executes all tasks in parallel, with completion handler called only when other tasks of same key are complete.
* For a given key, the order in which {@link #execute(Object, int, java.util.concurrent.Callable, Runnable, Runnable)} was called will be the order in which completion runnable will be called.
*/
public class DependentExecutor {
private final Executor executor;
private final Map<Object, Queue<DependentTask>> allTasks = new ArrayMap<>();
private final boolean enableDependency;
public DependentExecutor(boolean enableDependency, Executor executor) {
this.executor = executor;
this.enableDependency = enableDependency;
}
/**
* You should return true from the task on successful completion.
* If task returns false, then completion runnable wont be executed.
* <p/>
* This method will return false if tha task with this uniqueId already exists. Otherwise true is returned.
*
* @param key A non null key using which task dependency is decided. Tasks with same key are dependent.
* @param uniqueId If there is a task with this uniqueId already present, this task will be rejected
* @param task Optional. A long pending task to be performed or null if only completion is to be dependant.
* @param completionCallback A non null callback which will be serially executed for tasks with same key
* @param errorCallback If task returns false, then this callback will be invoked immediately (no dependency)
*/
public boolean execute(Object key, int uniqueId, Callable<Boolean> task, Runnable completionCallback, Runnable errorCallback) {
DependentTask queuedTask;
synchronized (allTasks) {
Queue<DependentTask> queue = allTasks.get(key);
for (Map.Entry<Object, Queue<DependentTask>> objectQueueEntry : allTasks.entrySet()) {
synchronized (objectQueueEntry.getValue()) {
Iterator<DependentTask> iterator = objectQueueEntry.getValue().iterator();
while (iterator.hasNext()) {
DependentTask dependentTask = iterator.next();
if (dependentTask.getUniqueId() == uniqueId) {
// no 2 tasks can have same uniqueID
return false;
}
}
}
}
if (queue == null && task == null) {
// this means we have no pending dependency as well as no task to perform. So only callback.
completionCallback.run();
return true;
} else if (queue == null) {
queue = new LinkedList<DependentTask>();
allTasks.put(key, queue);
}
if (!enableDependency) {
key = Math.random();
}
queuedTask = new DependentTask(key, uniqueId, queue, task, completionCallback, errorCallback);
queue.add(queuedTask);
}
executor.execute(queuedTask);
return true;
}
class DependentTask implements Runnable {
private final Queue<DependentTask> dependencyQueue;
private final Callable<Boolean> task;
private final Object key;
private final Runnable completionCallback;
private final Runnable errorCallback;
private final int uniqueId;
public DependentTask(Object key, int uniqueId, Queue<DependentTask> dependencyQueue, Callable<Boolean> task, Runnable completionCallback, Runnable errorCallback) {
this.uniqueId = uniqueId;
this.task = task;
this.dependencyQueue = dependencyQueue;
this.key = key;
this.completionCallback = completionCallback;
this.errorCallback = errorCallback;
}
public int getUniqueId() {
return uniqueId;
}
@Override
public void run() {
Boolean result = false;
try {
if (task != null) {
result = task.call();
} else {
result = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (result) {
synchronized (dependencyQueue) {
while (dependencyQueue.peek() != this) {
try {
dependencyQueue.wait(); // deadlock !!
} catch (InterruptedException e) {
}
}
}
completionCallback.run(); // by now we are the first element in the linked list. Lets call completion.
} else {
errorCallback.run(); // by now we are the first element in the linked list. Lets call error callback.
}
synchronized (dependencyQueue) {
dependencyQueue.remove(); //remove thyself
dependencyQueue.notifyAll();
}
// clean up of main map
synchronized (allTasks) {
if (dependencyQueue.isEmpty()) {
allTasks.remove(key);
}
}
}
}
}
}
/**
*并行执行所有任务,仅当具有相同键的其他任务完成时才调用完成处理程序。
*对于给定的键,调用{@link#execute(Object,int,java.util.concurrent.Callable,Runnable,Runnable)}的顺序将是调用completion Runnable的顺序。
*/
公共类从属执行器{
私人最终执行人;
private final Map allTasks=new ArrayMap();
私有最终布尔启用依赖;
公共DependentExecutor(布尔启用Dependency,Executor-Executor){
this.executor=执行人;
this.enableDependency=enableDependency;
}
/**
*成功完成任务后,应返回true。
*若任务返回false,则不会执行completion runnable。
*
*如果具有此唯一ID的任务已存在,则此方法将返回false。否则返回true。
*
*@param key决定任务依赖关系的非空键。具有相同键的任务是依赖的。
*@param uniqueId如果已经存在具有此uniqueId的任务,则此任务将被拒绝
*@param task可选。要执行的长挂起任务,如果仅依赖于完成,则为null。
*@param completionCallback一个非空回调,将对具有相同密钥的任务串行执行
*@param errorCallback如果任务返回false,则将立即调用此回调(无依赖项)
*/
公共布尔执行(对象键、int uniqueId、可调用任务、可运行的completionCallback、可运行的errorCallback){
依赖任务队列任务;
已同步(所有任务){
Queue Queue=allTasks.get(键);
对于(Map.Entry objectQueueEntry:allTasks.entrySet()){
已同步(objectQueueEntry.getValue()){
迭代器迭代器=objectQueueEntry.getValue().Iterator();
while(iterator.hasNext()){
DependentTask DependentTask=iterator.next();
if(dependentTask.getUniqueId()==uniqueId){
//没有两个任务可以具有相同的唯一ID
返回false;
}
}
}
}
if(队列==null&&task==null){
//这意味着我们没有挂起的依赖项,也没有要执行的任务,所以只有回调。
completionCallback.run();
返回true;
}else if(队列==null){
队列=新的LinkedList();
所有任务。放置(键、队列);
}
如果(!enableDependency){
key=Math.random();
}
queuedTask=新的DependentTask(键、唯一ID、队列、任务、completionCallback、errorCallback);
添加(queuedTask);
}
executor.execute(queuedTask);
返回true;
}
类DependentTask实现可运行{
私有最终队列依赖队列;
私有最终可调用任务;
私有最终对象密钥;
私有最终可运行的completionCallback;
私有最终可运行错误回调;
私人最终国际统一号;
public DependentTask(对象键、int uniqueId、队列dependencyQueue、可调用任务、可运行的completionCallback、可运行的errorCallback){
this.uniqueId=uniqueId;
this.task=任务;
this.dependencyQueue=dependencyQueue;
this.key=key;
this.completionCallback=completionCallback;
this.errorCallback=errorCallback;
}
public int getUniqueId(){
返回唯一标识;
}
@凌驾
公开募捐{
布尔结果=假;
试一试{
如果(任务!=null){
结果=task.call();
}否则{
结果=真;
}
}捕获(例外e){
e、 printStackTrace();
}最后{
如果(结果){
已同步(依赖队列){
while(dependencyQueue.peek()!=此){
试一试{
dependencyQueue.wait();//死锁!!
}捕捉(中断异常e){
}
}
}
completionCallback.run();//现在我们是链表中的第一个元素。让我们调用completion。
}否则{
errorCallback.run();//现在我们是链表中的第一个元素。让我们调用error callback。
}
已同步(依赖队列){
dependencyQueue.remove();//删除您自己
dependencyQueue.notifyAll();
}
//清理主地图
已同步(所有任务){
if(dependencyQueue.isEmpty()){
所有任务。删除(键);
}
}
}
}
}
}
问题#1
从队列中删除“self”的逻辑是错误的。您可以从队列中删除
synchronized (queue) {
queue.add(queuedTask);
}