如何使用notify?</v>唤醒RecursiveTask <v>

时间:2013-11-24 07:07:33

标签: java multithreading wait notify

我无法弄明白,当等待方法暂停执行这些任务时,如何唤醒由 ForkJoinPool 调用的 RecursiveTasks 。这是我使用方法 MainRecursionClass.resume 的简单示例,它不正确(不会唤醒RecursiveTasks)。

public class Program {
   public static void main(String[] args) {
      Program p = new Program();
      final MainRecursionClass mrc = p.new MainRecursionClass();

      //Thread outputs integers to simulate work
      new Thread() {
         public void run() {
            mrc.doJob();
         }
      }.start();

      //Thread performs wait and notify on MainRecursionClass object
      p.new PauseResume(mrc).start();
   }

/**
 * 
 * This class performs suspend and resume operations to the MainRecursionClass class object
 *
 */
   private class PauseResume extends Thread {
      private MainRecursionClass rv;

      public PauseResume(MainRecursionClass rv) {
         this.rv = rv;
      }

      @Override
      public void run() {
         while(!isInterrupted()) {
            try {
               sleep(4000);

               rv.suspend();
               sleep(8000);

               rv.resume();
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }
   }

   private class MainRecursionClass {
      private boolean pause = false;
      private MyRecursive rv;

      public void doJob() {
         rv = new MyRecursive(0, 100000);
         ForkJoinPool pool = new ForkJoinPool();      
         pool.invoke(rv);
      }

      public void suspend() {
         pause = true;

         System.out.println("Suspended");
      }

      /**
       * This method is incorrect. It should wake up all MyRecursive instances to continue their work.
       */
      public synchronized void resume() {
         pause = false;
         notifyAll();

         System.out.println("Resumed");
      }

      private class MyRecursive extends RecursiveTask<Object> {
         private static final long serialVersionUID = 1L;
         private int start;
         private int length;
         private int threshold = 15;

         public MyRecursive(int start, int length) {
            super();
            this.start = start;
            this.length = length;
         }

         protected void computeDirectly() throws Exception {
            for (int index = start; index < start + length; index++) {
               //PAUSE
               synchronized (this) {
                  try {
                     while(pause) {
                        wait();
                     }
                  } catch (InterruptedException e) {
                     e.printStackTrace();
                  }
               }
               //PAUSE

               //some output to simulate work...
               System.out.println(index);

               Thread.sleep(1000);
            }
         }

         /**
          * Recursion
          */
         @Override
         protected Object compute() {
            if (length <= threshold) {
               try {
                  computeDirectly();
               } catch (Exception e) {
                  return e;
               }

               return null;
            }

            int split = length / 2;

            invokeAll(new MyRecursive(start, split),
                      new MyRecursive(start + split, length - split));

            return null;
         }
      }
   }
}

2 个答案:

答案 0 :(得分:0)

您不应在线程池上运行的任务中使用wait / notify。如果你的池是有界的,那么它可能会导致线程饥饿(一种死锁形式)。如果它是无界的,则可以创建太多线程并且主内存耗尽。

相反,您应该将您的任务拆分为2(或更多)并根据其起始条件启动子任务。当你想要一个任务到wait()时,然后重构它以便当前的子任务退出,并准备好运行下一个子任务。

答案 1 :(得分:0)

最后,我找到了这个解决方案:我在List<MyRecursive> list = new ArrayList<>();中创建了MainRecursionClass对象,并在MyRecursive中添加了递归创建的每个list实例。班级MyRecursive有新方法:

public synchronized void resume() {
   notify();
}

什么时候,唤醒线程的方法MainRecursionClass.resume()看起来像这样:

public void resume() {
   System.out.println("Resumed");

   pause = false;
   for(MyRecursive mr : list) {
      if(mr != null)
         mr.resume();
      }
   }
}