Reputation: 2783
I got a project where I draw a complex form on a canvas, dependant on user input.
Now, calculating and drawing the form takes quite some time, so I put the calculating and drawing on separate threads:
First I calculate all the edges, then I draw them to a separate canvas, then I copy the content from the separate canvas to the screen-canvas.
calculation code
// 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);
}
Then I draw it with default code (using GraphicsContext), that code works, so I won't copy it here.
Then I copy the content to the screen with this:
SnapshotParameters params = new SnapshotParameters();
params.setFill(Color.TRANSPARENT);
WritableImage image = hiddenCanvas.snapshot(params, null);
kochPanel.getGraphicsContext2D().drawImage(image, 0, 0);
But here's my problem: no matter how I try, I always end up deadlocking the main thread: if I use join()
, it will wait for the threads to end. So then I thought: I can use a timer that checks if the threads are done like this:
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);
And that's when I found out that timers are on a separate thread as well.
So my question is: how can I make sure that I wait to draw to the canvas until all the threads are done doing their stuff, without blocking/deadlocking the main thread?
Below are just examples of how the GUI looks like, so you have an idea.
Upvotes: 1
Views: 108
Reputation: 419
Based on your code snippet, you'll need to extend TimerTask
providing your own implementation.
In your implementation pass a reference to the object responsible for accessing the running
variable through it's constructor and then check for running
through this object.
Upvotes: 1
Reputation: 1819
If you dont want to use join, you can use monitors to control the thread execution
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();
}
}
You would construct this object with the number of threads you will launch. When each thread is finished, it will call updateFinishedThread()
. The main thread should call awaitThreads()
after it launches the computation threads.
Upvotes: 1