How to update java GUI from Thread? - java

private void StartActionPerformed(java.awt.event.ActionEvent evt) {
Queue queue=new Queue();
int target=Integer.parseInt(Target.getText());
String path=Path.getText();
final Producer p=new Producer(queue, target);
Consumer c=new Consumer(queue);
p.start();
c.start();
while(p.finish !=true)
{
Runnable r = new Runnable() {
public void run() {
ProgressPrecent.setValue(Producer.ProgressPercent);
}
};
if(EventQueue.isDispatchThread()) {
r.run();
}
else {
EventQueue.invokeLater(r);
}
}
}
I have two classes that have a shared Queue. one of them is Producer that produces till a target other one consume those elements. all of two extends Thread. I want to display the progress percent to the user, but it freeze my GUI so what should I do?

Worker Threads by default never to invoked EventDispatchThread, you have issue with Concurency in Swing
all updates to Swing GUI must be done on EDT
Runnable could be proper way but ProgressPrecent.setValue(Producer.ProgressPercent); must be wrapped in invokeLater
code
SwingUtilities.invokeLater(new Runnable(){
public void run(){
ProgressPrecent.setValue(Producer.ProgressPercent);
}
});
remove testing for EDT,
code lines
if(EventQueue.isDispatchThread()) {
r.run();
}
Workers Thread by defaut never ever to invoke EDT, then doesn't matter if is started from EDT, nor tested for isDispatchThread() doesn't make me some sence
never ever, don't to use Thread.sleep(int) inside Swing Listeners, because caused freeze Swing GUI too
I think you can to use SwingWorker for this job too

I think you will have to put the whole while loop into a thread. Otherwise the loop will block your ActionEvent and thus freezes the UI.
Something like:
new Thread(){
public void run(){
while(!p.finish){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
ProgressPrecent.setValue(Producer.ProgressPercent);
}
});
try{
Thread.sleep(100);
}catch(...){}
}
}
}.start();

Related

Java operations in Swing thread

I have a problem.
Here is the code:
JButton buttonChangeServer = new JButton("Change server");
buttonChangeServer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getLobbies();
}
}
});
private void getLobbies() {
lobbyListModel.removeAllElements();
statusLabel.setText("Connecting...");
final ArrayList<LobbyInfo> lobbyInfos =
UserClient.getLobbies(host, action, null);
if (lobbyInfos != null) {
setLobbies(lobbyInfos);
statusLabel.setText("Sucessfully got lobby list from " + getHost());
}
else {
statusLabel.setText("Failed to connect to " + getHost());
}
}
The UserClient.getLobbies(host, action, null) method executes for a 3 seconds (timeout) if it can not establish connection.
The problem is that this two operations
lobbyListModel.removeAllElements();
statusLabel.setText("Connecting...");
are not visible while executing.
I suppose that the problem is that the method getLobbies() in actionPerformed(ActionEvent e) executes in Swing thread, and all the GUI operations are not being shown till the end of the execution of the getLobbies();
My aim is to show all the changes of GUI, before and after the execution of UserClient.getLobbies(host, action, null);. How can I manage that? Is there an easy way to show all of them? Thank you.
P.S. One of the solutions may be putting that potentionally long operation in another thread, like this:
private void getLobbies() {
lobbyListModel.removeAllElements();
statusLabel.setText("Connecting...");
new Thread(new Runnable() {
#Override
public void run() {
final ArrayList<LobbyInfo> lobbyInfos =
UserClient.getLobbies(host, action, null);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (lobbyInfos != null) {
setLobbies(lobbyInfos);
statusLabel.setText("Sucessfully got lobby list from " + getHost());
}
else {
statusLabel.setText("Failed to connect to " + getHost());
}
}
});
}
}).start();
}
It works, but it is rather complicated. Are there any ways easier?
One of the solutions may be putting that potentially long operation in another thread
Yes, long operations (or blocking operations) should not execute on the EDT.
So you do need to execute the long running task on a separated Thread. Check out the section from the Swing tutorial on Worker Threads and Swing Worker for the Swing solution to this problem.
When your query finishes executing you can "publish" the results so the code is executed on the EDT when the Swing components are updated.

How to notify another thread

I want to know the best way how to notify another thread. For example, I have a background thread:
public void StartBackgroundThread(){
new Thread(new Runnable() {
#Override
public void run() {
//Do something big...
//THEN HOW TO NOTIFY MAIN THREAD?
}
}).start();
}
When it finished it has to notify main thread? If somebody knows the best way how to do this I'll appreciate it!
The typical answer is a BlockingQueue. Both BackgroundThread (often called the Producer) and MainThread (often called the Consumer) share a single instance of the queue (perhaps they get it when they are instantiated). BackgroundThread calls queue.put(message) each time it has a new message and MainThread calls 'queue.take()which will block until there's a message to receive. You can get fancy with timeouts and peeking but typically people want aBlockingQueueinstance such asArrayBlockingQueue`.
Purely based on your question you could do this:
public class test
{
Object syncObj = new Object();
public static void main(String args[])
{
new test();
}
public test()
{
startBackgroundThread();
System.out.println("Main thread waiting...");
try
{
synchronized(syncObj)
{
syncObj.wait();
}
}
catch(InterruptedException ie) { }
System.out.println("Main thread exiting...");
}
public void startBackgroundThread()
{
(new Thread(new Runnable()
{
#Override
public void run()
{
//Do something big...
System.out.println("Background Thread doing something big...");
//THEN HOW TO NOTIFY MAIN THREAD?
synchronized(syncObj)
{
System.out.println("Background Thread notifing...");
syncObj.notify();
}
System.out.println("Background Thread exiting...");
}
})).start();
}
}
and see this output
PS C:\Users\java> javac test.java
PS C:\Users\java> java test
Main thread waiting...
Background Thread doing something big...
Background Thread notifing...
Background Thread exiting...
Main thread exiting...
Just call notify()
public void run() {
try {
while ( true ) {
putMessage();
sleep( 1000 );
}
}
catch( InterruptedException e ) { }
}
private synchronized void putMessage() throws InterruptedException {
while ( messages.size() == MAXQUEUE )
wait();
messages.addElement( new java.util.Date().toString() );
notify();
}
You can't "notify the main thread".
The best approach is to use an ExecutorService, like this for example:
import java.util.concurrent.*;
// in main thread
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(new Runnable() {
#Override
public void run() {
//Do something big...
}
});
future.get(); // blocks until the Runnable finishes
The classes are written specially to deal with asynchronous operations, and all the code in there is already written for you and bullet-proof.
Edit
If you don't want to block the main thread while waiting, wait within another thread:
final Future<?> future = executorService.submit(new Runnable() {
#Override
public void run() {
//Do something big...
}
});
new Thread(new Runnable() {
#Override
public void run() {
future.get(); // blocks until the other Runnable finishes
// Do something after the other runnable completes
}
}).start();
One thread notifying another thread is not a good way to do it. Its better to have 1 master thread that gives the slave thread work. The slave thread is always running and waits until it receives work. I recommend that you draw two columns and determine exactly where each thread needs to wait.
public void run()
{
//Do something big...
synchronized(this)
{
done = true;
}
}
Java includes libraries that make this really easy see ExecutorService and the following post
Producer/Consumer threads using a Queue

Simple way to wait for a method to finish before starting another one

I'm not familiar at all with Java threading :(. I have this class which, when called, constructs a new window (draw() method). The drawGUI() calls a processing method at the end (compare() method).
basically the structure is
public static void draw() {
// draws stuff
compare();
}
The problem is that the window drawn by drawGUI() has some major visual artifacts till the processing (compare() ) is over.
What is the simplest way I can implement to launch compare() after draw() has finished executing? Thank you
The simplest way is to just put your draw() code inside an asyncExec() inside your thread at the end
new Thread(new Runnable() {
public void run() {
//do long running blocking bg stuff here
Display.getDefault().asyncExec(new Runnable() {
public void run() {
draw();
}
}
}).start();
Assuming that the reason you're getting the artefacts is that draw() hasn't had a chance to return, you can use a Thread.
final T parent = this;
new Thread(new Runnable() {
public void run() {
parent.compare();
}
}).start();
(Where T is the type of the class that has your compare method).

Run thread only for one minute in java

What the best practice to run thread only for some period?
I can easily check curentTime and close the thread after in worked for some time, but I think it's not the right way.
It depends on what you want to achieve, but generally speaking the approach you mentioned with measuring the time from the start is not that wrong.
I would code it like this:
private static class MyTimerTask extends TimerTask {
private final Thread target;
public MyTimerTask(Thread target) { this.target = target; }
public void run() {
target.interrupt();
}
}
public void run() {
Thread final theThread = Thread.currentThread();
Timer timer = new Timer();
try {
timer.schedule(new MyTimerTask(theThread), 60000});
while(!theThread.interrupted()) {
....
}
} finally {
timer.cancel();
}
}
... which is Hovercraft described, except using interrupt instead of an ad-hoc flag. Using interrupts has the advantage that some I/O calls are unblocked by an interrupt, and some libraries will respect it.
I'm surprised (and deeply disappointed) that no one has mentioned the Executors framework. It has usurped the Timer framework (or at least the java.util.Timer class) as the "goto" for scheduled tasks.
For instance,
// Start thread
final Thread t = new Thread(new Runnable(){
#Override
public void run(){
while(!Thread.currentThread().isInterrupted()){
try{
// do stuff
}
catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}
}
});
t.start();
// Schedule task to terminate thread in 1 minute
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.schedule(new Runnable(){
#Override
public void run(){
t.interrupt();
}
}, 1, TimeUnit.MINUTES);

Waiting for all Runnables submitted to SWT UI thread with Display::asyncExec() to finish

Is there a way to wait for all Runnables submitted to the SWT UI Thread via asyncExec(...) to finish?
Background:
I have a long-running operation, which among other things is triggering events that in turn submit Runnables to the SWT UI thread via the asyncExec(...) instance method of Display.
The progress of the long-running operation is shown in a ProgressMonitorDialog, and I would like to close the dialog only after the UI thread has finished executing the Runnables.
Changing the calls from asyncExec(...) to syncExec(...) is not an option, as the latter is not desired when the events are triggered from other contexts.
org.eclipse.swt.widgets.Display.readAndDispatch() will process an event from the event queue and return false if there are no more events to process. But you probably don't want to use this as it processes an event.
asyncExec(*) is a FIFO queue (although OS graphics events supersede the asyncExecs), so you could do most of your long-running op processing and then place a final asyncExec in the queue:
final boolean[] done = new boolean[1];
Runnable r = new Runnable() {
public void run() {
done[0] = true;
}
};
// now wait for the event somehow. The brute force method:
while (!done[0]) {
Thread.sleep(200);
}
In theory, all of the other asyncExecs spawned from your long running op will be finished by the time you get to the last one.
EDIT: potential other option
Create your own org.eclipse.core.runtime.jobs.Job and then join() it at the end:
public static class RefCountJob extends Job {
public RefCountJob() {
super("REF_COUNT");
}
int count = 0;
public void increment() {
count++;
}
public void decrement() {
count--;
}
#Override
protected IStatus run(IProgressMonitor monitor) {
monitor.beginTask("WAITING", IProgressMonitor.UNKNOWN);
while (count > 0) {
Thread.sleep(200);
monitor.worked(1);
}
monitor.done();
return Status.OK_STATUS;
}
}
To use it, increment() it every time you are going to fire off events, and have them decrement it when they're done (You have to make sure they decrement it no matter what exception is thrown :-)
RefCountJob ref = new RefCountJob();
// ... do stuff, everybody increments and decrements ref
ref.increment();
// ... do more stuff
ref.increment();
// at the end of your long-running job
ref.schedule();
ref.join();
Thanks, I ended up with the following. I think it is a pretty clean solution. By the way I would upvote your answer if I had enough reputation for that :)
public class SWTThreadingUtils
{
public static void waitForAsyncExecsToFinish(Display display)
{
Object waitObj = new Object();
display.asyncExec(new DummyRunnable(waitObj));
synchronized (waitObj)
{
try {
waitObj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private static class DummyRunnable implements Runnable
{
private Object waitObj;
public DummyRunnable(Object waitObj)
{
this.waitObj = waitObj;
}
#Override
public void run()
{
synchronized (waitObj)
{
waitObj.notify();
}
}
}
}

Categories