我有一个项目,我在画布上绘制一个复杂的表单,取决于用户输入。
现在,计算和绘制表单需要相当长的时间,所以我将计算和绘图放在不同的线程上:
首先我计算所有边缘,然后将它们绘制到一个单独的画布上,然后将内容从单独的画布复制到屏幕画布。
计算代码
// Make 3 new threads. each thread calculates an edge.
Thread thread1 = new Thread(new RunnableClass("L", nxt, edges, application));
Thread thread2 = new Thread(new RunnableClass("R", nxt, edges, application));
Thread thread3 = new Thread(new RunnableClass("B", nxt, edges, application));
thread1.start();
thread2.start();
thread3.start();
// The code waits here until all Threads are finished.
try
{
thread1.join();
thread2.join();
thread3.join();
} catch (InterruptedException ex)
{
Logger.getLogger(KochManager.class.getName()).log(Level.SEVERE, null, ex);
}
然后我使用默认代码(使用GraphicsContext)绘制它,该代码有效,所以我不会在这里复制它。
然后我将内容复制到屏幕上:
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
WritableImage image = hiddenCanvas.snapshot(params, null);
kochPanel.getGraphicsContext2D().drawImage(image, 0, 0);
但这是我的问题:无论我如何尝试,我总是最终使主线程死锁:如果我使用join()
,它将等待线程结束。所以我想:我可以使用一个计时器来检查线程是否像这样完成:
timer.scheduleAtFixedRate(new TimerTask()
{
@Override
public void run()
{
if (running == false) {
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
WritableImage image = hiddenCanvas.snapshot(params, null);
kochPanel.getGraphicsContext2D().drawImage(image, 0, 0);
application.setTextCalc( String.valueOf(timeStampCalc.toString()));
application.setTextDraw(timeStampDraw.toString());
application.setTextNrEdges(String.valueOf(kf.getNrOfEdges()));
}
}
}, 0, 250);
当我发现定时器也在一个单独的线程上时。
所以我的问题是:我怎么能确保我等到绘制画布直到所有线程完成它们的东西,而没有阻塞/死锁主线程?
答案 0 :(得分:1)
如果您不想使用join,可以使用监视器来控制线程执行
.sum()
您将使用要启动的线程数构造此对象。每个线程完成后,它将调用class ThreadJoiner`
{
private int numThreads;
private int finishedThreads;
public ThreadJoiner(int numThreads)
{
this.numThreads = numThreads;
}
public synchronized void updateFinishedThread() throws Exception
{
this.finishedThreads++;
notify();
}
public synchronized void awaitThreads() throws Exception
{
while(this.finishedThreads < this.numThreads)
wait();
}
}
。主线程在启动计算线程后应调用updateFinishedThread()
。
答案 1 :(得分:1)
根据您的代码段,您需要扩展TimerTask
,提供您自己的实现。
在您的实现中,通过它的构造函数传递对负责访问running
变量的对象的引用,然后通过此对象检查running
。