我无法弄明白,当等待方法暂停执行这些任务时,如何唤醒由 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;
}
}
}
}
答案 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();
}
}
}