Is it feasible to implement some util method to suspend test (current thread) execution until application becomes idle?
Idle means:
1. there were no GUI events added to event queue for some period of time
2. there were no worker threads running any tasks for the same period of time.
Could you please provide implementation/code snippets to track previous conditions of idleness?
You can replace the EventQueue with your own implementation, as shown here. The variation below adds an idle() method that relies on an arbitrary THRESHOLD of 1000 ms.
import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JTree;
/**
* #see https://stackoverflow.com/questions/7976967
* #see https://stackoverflow.com/questions/3158254
*/
public class EventQueueTest {
public static void main(String[] args) throws
InterruptedException, InvocationTargetException {
EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
final MyEventQueue q = new MyEventQueue();
eventQueue.push(q);
EventQueue.invokeAndWait(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JTree());
f.pack();
f.setVisible(true);
}
});
// Test idle() on initial thread
for (int i = 0; i < 10; i++) {
Thread.sleep(2 * MyEventQueue.THRESHOLD);
System.out.println("Idle: " + q.idle());
}
}
private static class MyEventQueue extends EventQueue {
private static final int THRESHOLD = 1 * 1000;
private long last;
#Override
public void postEvent(AWTEvent e) {
super.postEvent(e);
last = System.currentTimeMillis();
}
public boolean idle() {
return System.currentTimeMillis() - last > THRESHOLD;
}
}
}
You can use Toolkit.getDefaultToolkit().addAWTEventListener(listener, eventMask) to subscribe to AWT event queue, so you can detect whether events are not added for some period of time.
I think that you need your custom code to monitor working threads, i.e. something in the beginning and end of run() method.
The problem is to "suspend the test execution". If your test is running in thread theoretically you can invoke the thread's suspend() method. But it is deprecated and should not be used. To perform clear implementation you should make your custom code that asks status during execution of the thread and calls wait() once it detects that the test must be suspended. When your code that monitors AWT event queue and working threads decides that test may be resumed it should call appropriate notify().
Probably better solution from design point of view is Actors model. There are several java framework that provide this functionality.
Related
This is simplified code, which would be called from pressing a button in my main JFrame class. Using this code, and then dismissing one of the resulting dialogs, causes all of my active windows in my Java session to either lock up or just go away.
//Broken code
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
List<JFrame> frameList = new ArrayList<>();
frameList.add(new TestJFrame());
frameList.add(new TestJFrame());
frameList.forEach(frame -> frame.setVisible(true));
frameList.forEach(frame -> {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(frame, "Msg", "Title", 0);
frame.setVisible(false);
frame.dispose();
});
});
}
However, if I were to remove the SwingUtilities.invokeLater() section then it works like I would expect (dialog pops up, close the dialog, window goes away, repeat).
//Working code
private void buttonActionPerformed(java.awt.event.ActionEvent evt) {
List<JFrame> frameList = new ArrayList<>();
frameList.add(new TestJFrame());
frameList.add(new TestJFrame());
frameList.forEach(frame -> frame.setVisible(true));
frameList.forEach(frame -> {
//SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(frame, "Msg", "Title", 0);
frame.setVisible(false);
frame.dispose();
//});
});
}
I'd rather not use the second one because the actual code is being started in a background thread that is notifying a set of listeners, so if I were to use the second one then it would block up the thread and slow down listeners until the user responds (when I could be processing during that time). What about the invokeLater() is breaking me? Is this expected behavior?
NOTE: This is simplified code pulled out of how I'm actually using it, but the core issue still exists (I have multiple JFrames, and if multiple JOptionPane.showMessageDialog()s were put on invokeLater()s for different JFrames then it breaks me. I tested the above code with a new, isolated, JFrame class created in Netbeans and was able to reproduce the error.
EDIT: I can't seem to reproduce the error in Windows, only seems to happen in Linux.
It is most likely invokeLater() which is breaking your code. If you want to thread this action try using a simple thread or
EventQueue.invokeLater(new Runnable()
{
public void run()
{ //Your joptionpane here
}
});`
Instead of invoke later i prefer using a
1) simple thread
2) TimerTask
3) ScheduledExecutorService
Use one of these methods.
This is an example for using timer task
import java.util.Timer;
import java.util.TimerTask;
public class Task2 {
public static void main(String[] args) {
TimerTask task = new TimerTask() {
#Override
public void run() {
// task to run goes here
System.out.println("Hello !!!");
}
};
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 1 * 1000;
// schedules the task to be run in an interval
timer.scheduleAtFixedRate(task, delay,
intevalPeriod);
} // end of main
}
If you are not satisfied you can use invoke later.
But remember never use invoke and wait its a bad idea
Here is my approach, as I understand the problem is on the locked windows, which are waiting for an event to finish, in swing the events are related with the AWT-EventQueue.
Here is a little explanation about: https://stackoverflow.com/a/22534931/1670134
So, in order to get your window working I used the Future type:
From the java doc:
A Future represents the result of an asynchronous computation. Methods
are provided to check if the computation is complete, to wait for its
completion, and to retrieve the result of the computation. The result
can only be retrieved using method get when the computation has
completed, blocking if necessary until it is ready.
package com.stackoverflow.future;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import com.stackoverflow.frame.MyFrame;
public class MySwingWorker extends SwingWorker<Void, Void>{
#Override
protected Void doInBackground() throws Exception {
final ExecutorService service = Executors.newFixedThreadPool(1);
List<Future<JFrame>> frameList = new ArrayList<Future<JFrame>>();
frameList.add(service.submit(new SwingLoader(new MyFrame())));
frameList.add(service.submit(new SwingLoader(new MyFrame())));
try {
service.shutdown();
service.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
service.shutdownNow();
}
return null;
}
public static void main(String[] args) {
MySwingWorker mySwingWorker = new MySwingWorker();
SwingUtilities.invokeLater(mySwingWorker);
}
}
The loader:
package com.stackoverflow.future;
import java.util.concurrent.Callable;
import javax.swing.JFrame;
public class SwingLoader implements Callable<JFrame>{
private JFrame frame;
public SwingLoader(JFrame frame){
this.frame = frame;
}
#Override
public JFrame call() throws Exception {
frame.setVisible(true);
return frame;
}
}
NOTE: This code is just a proto, in order to provide you with ideas and it must be modified and cleaned in order to achieve the desired results.
Here you are a link with a couple of explanations of each type:
http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/
I have been working with SwingWorkers for a while and have ended up with a strange behavior, at least for me. I clearly understand that due to performance reasons several invocations to publish() method are coallesced in one invocation. It makes perfectly sense to me and I suspect SwingWorker keeps some kind of queue to process all that calls.
According to tutorial and API, when SwingWorker ends its execution, either doInBackground() finishes normally or worker thread is cancelled from the outside, then done() method is invoked. So far so good.
But I have an example (similar to shown in tutorials) where there are process() method calls done after done() method is executed. Since both methods execute in the Event Dispatch Thread I would expect done() be executed after all process() invocations are finished. In other words:
Expected:
Writing...
Writing...
Stopped!
Result:
Writing...
Stopped!
Writing...
Sample code
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Demo {
private SwingWorker<Void, String> worker;
private JTextArea textArea;
private Action startAction, stopAction;
private void createAndShowGui() {
startAction = new AbstractAction("Start writing") {
#Override
public void actionPerformed(ActionEvent e) {
Demo.this.startWriting();
this.setEnabled(false);
stopAction.setEnabled(true);
}
};
stopAction = new AbstractAction("Stop writing") {
#Override
public void actionPerformed(ActionEvent e) {
Demo.this.stopWriting();
this.setEnabled(false);
startAction.setEnabled(true);
}
};
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(new JButton(startAction));
buttonsPanel.add(new JButton(stopAction));
textArea = new JTextArea(30, 50);
JScrollPane scrollPane = new JScrollPane(textArea);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(scrollPane);
frame.add(buttonsPanel, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void startWriting() {
stopWriting();
worker = new SwingWorker<Void, String>() {
#Override
protected Void doInBackground() throws Exception {
while(!isCancelled()) {
publish("Writing...\n");
}
return null;
}
#Override
protected void process(List<String> chunks) {
String string = chunks.get(chunks.size() - 1);
textArea.append(string);
}
#Override
protected void done() {
textArea.append("Stopped!\n");
}
};
worker.execute();
}
private void stopWriting() {
if(worker != null && !worker.isCancelled()) {
worker.cancel(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGui();
}
});
}
}
SHORT ANSWER:
This happens because publish() doesn't directly schedule process, it sets a timer which will fire the scheduling of a process() block in the EDT after DELAY. So when the worker is cancelled there is still a timer waiting to schedule a process() with the data of the last publish. The reason for using a timer is to implement the optimization where a single process may be executed with the combined data of several publishes.
LONG ANSWER:
Let's see how publish() and cancel interact with each other, for that, let us dive into some source code.
First the easy part, cancel(true):
public final boolean cancel(boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}
This cancel ends up calling the following code:
boolean innerCancel(boolean mayInterruptIfRunning) {
for (;;) {
int s = getState();
if (ranOrCancelled(s))
return false;
if (compareAndSetState(s, CANCELLED)) // <-----
break;
}
if (mayInterruptIfRunning) {
Thread r = runner;
if (r != null)
r.interrupt(); // <-----
}
releaseShared(0);
done(); // <-----
return true;
}
The SwingWorker state is set to CANCELLED, the thread is interrupted and done() is called, however this is not SwingWorker's done, but the future done(), which is specified when the variable is instantiated in the SwingWorker constructor:
future = new FutureTask<T>(callable) {
#Override
protected void done() {
doneEDT(); // <-----
setState(StateValue.DONE);
}
};
And the doneEDT() code is:
private void doneEDT() {
Runnable doDone =
new Runnable() {
public void run() {
done(); // <-----
}
};
if (SwingUtilities.isEventDispatchThread()) {
doDone.run(); // <-----
} else {
doSubmit.add(doDone);
}
}
Which calls the SwingWorkers's done() directly if we are in the EDT which is our case. At this point the SwingWorker should stop, no more publish() should be called, this is easy enough to demonstrate with the following modification:
while(!isCancelled()) {
textArea.append("Calling publish\n");
publish("Writing...\n");
}
However we still get a "Writing..." message from process(). So let us see how is process() called. The source code for publish(...) is
protected final void publish(V... chunks) {
synchronized (this) {
if (doProcess == null) {
doProcess = new AccumulativeRunnable<V>() {
#Override
public void run(List<V> args) {
process(args); // <-----
}
#Override
protected void submit() {
doSubmit.add(this); // <-----
}
};
}
}
doProcess.add(chunks); // <-----
}
We see that the run() of the Runnable doProcess is who ends up calling process(args), but this code just calls doProcess.add(chunks) not doProcess.run() and there's a doSubmit around too. Let's see doProcess.add(chunks).
public final synchronized void add(T... args) {
boolean isSubmitted = true;
if (arguments == null) {
isSubmitted = false;
arguments = new ArrayList<T>();
}
Collections.addAll(arguments, args); // <-----
if (!isSubmitted) { //This is what will make that for multiple publishes only one process is executed
submit(); // <-----
}
}
So what publish() actually does is adding the chunks into some internal ArrayList arguments and calling submit(). We just saw that submit just calls doSubmit.add(this), which is this very same add method, since both doProcess and doSubmit extend AccumulativeRunnable<V>, however this time around V is Runnable instead of String as in doProcess. So a chunk is the runnable that calls process(args). However the submit() call is a completely different method defined in the class of doSubmit:
private static class DoSubmitAccumulativeRunnable
extends AccumulativeRunnable<Runnable> implements ActionListener {
private final static int DELAY = (int) (1000 / 30);
#Override
protected void run(List<Runnable> args) {
for (Runnable runnable : args) {
runnable.run();
}
}
#Override
protected void submit() {
Timer timer = new Timer(DELAY, this); // <-----
timer.setRepeats(false);
timer.start();
}
public void actionPerformed(ActionEvent event) {
run(); // <-----
}
}
It creates a Timer that fires the actionPerformed code once after DELAY miliseconds. Once the event is fired the code will be enqueued in the EDT which will call an internal run() which ends up calling run(flush()) of doProcess and thus executing process(chunk), where chunk is the flushed data of the arguments ArrayList. I skipped some details, the chain of "run" calls is like this:
doSubmit.run()
doSubmit.run(flush()) //Actually a loop of runnables but will only have one (*)
doProcess.run()
doProcess.run(flush())
process(chunk)
(*)The boolean isSubmited and flush() (which resets this boolean) make it so additional calls to publish don't add doProcess runnables to be called in doSubmit.run(flush()) however their data is not ignored. Thus executing a single process for any amount of publishes called during the life of a Timer.
All in all, what publish("Writing...") does is scheduling the call to process(chunk) in the EDT after a DELAY. This explains why even after we cancelled the thread and no more publishes are done, still one process execution appears, because the moment we cancel the worker there's (with high probability) a Timer that will schedule a process() after done() is already scheduled.
Why is this Timer used instead of just scheduling process() in the EDT with an invokeLater(doProcess)? To implement the performance optimization explained in the docs:
Because the process method is invoked asynchronously on the Event
Dispatch Thread multiple invocations to the publish method might occur
before the process method is executed. For performance purposes all
these invocations are coalesced into one invocation with concatenated
arguments.
For example:
publish("1");
publish("2", "3");
publish("4", "5", "6");
might result in:
process("1", "2", "3", "4", "5", "6")
We now know that this works because all the publishes that occur within a DELAY interval are adding their args into that internal variable we saw arguments and the process(chunk) will execute with all that data in one go.
IS THIS A BUG? WORKAROUND?
It's hard to tell If this is a bug or not, It might make sense to process the data that the background thread has published, since the work is actually done and you might be interested in getting the GUI updated with as much info as you can (if that's what process() is doing, for example). And then it might not make sense if done() requires to have all the data processed and/or a call to process() after done() creates data/GUI inconsistencies.
There's an obvious workaround if you don't want any new process() to be executed after done(), simply check if the worker is cancelled in the process method too!
#Override
protected void process(List<String> chunks) {
if (isCancelled()) return;
String string = chunks.get(chunks.size() - 1);
textArea.append(string);
}
It's more tricky to make done() be executed after that last process(), for example done could just use also a timer that will schedule the actual done() work after >DELAY. Although I can't think this is would be a common case since if you cancelled It shouldn't be important to miss one more process() when we know that we are in fact cancelling the execution of all the future ones.
Having read DSquare's superb answer, and concluded from it that some subclassing would be needed, I've come up with this idea for anyone who needs to make sure all published chunks have been processed in the EDT before moving on.
NB I tried to write it in Java rather than Jython (my language of choice and officially the best language in the world), but it is a bit complicated because, for example, publish is final, so you'd have to invent another method to call it, and also because you have to (yawn) parameterise everything with generics in Java.
This code should be understandable by any Java person: just to help, with self.publication_counter.get(), this evaluates to False when the result is 0.
# this is how you say Worker... is a subclass of SwingWorker in Python/Jython
class WorkerAbleToWaitForPublicationToFinish( javax.swing.SwingWorker ):
# __init__ is the constructor method in Python/Jython
def __init__( self ):
# we just add an "attribute" (here, publication_counter) to the object being created (self) to create a field of the new object
self.publication_counter = java.util.concurrent.atomic.AtomicInteger()
def await_processing_of_all_chunks( self ):
while self.publication_counter.get():
time.sleep( 0.001 )
# fully functional override of the Java method
def process( self, chunks ):
for chunk in chunks:
pass
# DO SOMETHING WITH EACH CHUNK
# decrement the counter by the number of chunks received
# NB do this AFTER dealing with the chunks
self.publication_counter.addAndGet( - len( chunks ) )
# fully functional override of the Java method
def publish( self, *chunks ):
# increment the counter by the number of chunks received
# NB do this BEFORE publishing the chunks
self.publication_counter.addAndGet( len( chunks ))
self.super__publish( chunks )
So in your calling code, you put something like:
engine.update_xliff_task.get()
engine.update_xliff_task.await_processing_of_all_chunks()
PS the use of a while clause like this (i.e. a polling technique) is hardly elegant. I looked at the available java.util.concurrent classes such as CountDownLatch and Phaser (both with thread-blocking methods), but I don't think either would suit for this purpose...
later
I was interested enough in this to tweak a proper concurrency class (written in Java, found on the Apache site) called CounterLatch. Their version stops the thread at await() if a value of an AtomicLong counter is reached. My version here allows to you to either to do that, or the opposite: to say "wait until the counter reaches a certain value before lifting the latch":
NB use of AtomicLong for signal and AtomicBoolean for released: because in the original Java they use the volatile keyword. I think using the atomic classes will achieve the same purpose.
class CounterLatch():
def __init__( self, initial = 0, wait_value = 0, lift_on_reached = True ):
self.count = java.util.concurrent.atomic.AtomicLong( initial )
self.signal = java.util.concurrent.atomic.AtomicLong( wait_value )
class Sync( java.util.concurrent.locks.AbstractQueuedSynchronizer ):
def tryAcquireShared( sync_self, arg ):
if lift_on_reached:
return -1 if (( not self.released.get() ) and self.count.get() != self.signal.get() ) else 1
else:
return -1 if (( not self.released.get() ) and self.count.get() == self.signal.get() ) else 1
def tryReleaseShared( self, args ):
return True
self.sync = Sync()
self.released = java.util.concurrent.atomic.AtomicBoolean() # initialised at False
def await( self, *args ):
if args:
assert len( args ) == 2
assert type( args[ 0 ] ) is int
timeout = args[ 0 ]
assert type( args[ 1 ] ) is java.util.concurrent.TimeUnit
unit = args[ 1 ]
return self.sync.tryAcquireSharedNanos(1, unit.toNanos(timeout))
else:
self.sync.acquireSharedInterruptibly( 1 )
def count_relative( self, n ):
previous = self.count.addAndGet( n )
if previous == self.signal.get():
self.sync.releaseShared( 0 )
return previous
So my code now looks like this:
In the SwingWorker constructor:
self.publication_counter_latch = CounterLatch()
In SW.publish:
self.publication_counter_latch.count_relative( len( chunks ) )
self.super__publish( chunks )
In the thread waiting for chunk processing to stop:
worker.publication_counter_latch.await()
I'm trying to display the time in a jpanel while a background thread performs an expensive operation. Obviously the time thread should get a higher priority than the background thread to display the time accurately.
I've written the following solution, but I'm sure it can be done better. What are your suggestions ?
Also: How do I shut down the background thread correctly without using .stop() ?
Edit: After having tested the program without priority settings it also works, but I don't really know why.
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class Test1 extends JPanel{
private static final long serialVersionUID = 1L;
private int time = 23*3600+59*60+30;
private Thread operationThread;
public Test1(){
JLabel text = new JLabel();
Timer timeDisplayer = new Timer(1000, e -> {
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
text.setText((time/3600)%24+":"+(time/60)%60+":"+(time%60));
time+=1;
});
timeDisplayer.setInitialDelay(0);
JButton b = new JButton("Restart operation");
b.addActionListener(arg0 -> makeNewThread());
add(b);
add(text);
timeDisplayer.start();
}
private void makeNewThread(){
if(operationThread!=null && operationThread.isAlive())
operationThread.stop();
operationThread = new Thread(() -> {
//Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
//expensiveOperation();
});
operationThread.start();
}
public static void main(String[] args){
JFrame f = new JFrame();
Test1 t = new Test1();
f.setLocation(400,50);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setSize(100,100);
f.setContentPane(t);
f.setVisible(true);
}
}
Generally, things that you display (e.g. a timer), do not have to refresh that fast to get something that is visually appealing. A one second delay is a huge amount of time in computer time, so it is not necessary to give the timer update thread extra priority.
Your usage if the swing Timer class can be improved significantly. The way the timer works is to fire an ActionEvent to your handler, which is queued up on the the event-dispatching thread. This means that there can be a delay between the event firing and the execution of your listener. A better way to handle that is to store the value of System.currentTimeMillis somewhere and use it in your callback:
...
private long startMillis;
public Test1()
{
...
Timer timeDisplayer = new Timer(1000, e -> {
time = (System.currentTimeMillis() - startMillis + 500L) / 1000L;
text.setText(((time / 3600) % 24) + ":" + ((time / 60) % 60) + ":" + (time % 60));
});
timeDisplayer.setInitialDelay(0);
...
startMillis = System.currentTimeMillis()
timeDisplayer.start();
}
This has the additional advantage that you can speed up your timer as much as you want, add sub-second precision, etc. If you do decide to do that, it may be better to delay the time computation as much as possible, e.g., by overriding the paintComponent() method of the component displaying the time.
As far as stopping the thread goes, I suggest a simple interrput-based mechanism to avoid using the deprecated stop() method. Rather than using stop(), use interrupt() on the expensive computation thread. This will generally (but read the docs) do one of two things:
Throw an interrupted exception in the computation thread.
Set the thread's interrupt status.
It is then your computation's job to respond to both of those cases. Usually, you would enclose the expensive part in a try-catch block and make attempts to check interrupt status periodically. Here is an example:
private expensiveOperation()
{
try {
for(SomeObject among : millionsOfItems) {
// Do stuff
if(Thread.currentThread().interrupted()) {
// Possibly log the interruption as you would for the exception
break;
}
}
} catch(InterruptedException ie) {
// Probably just ignore or log it somehow since this is really a normal condition
} finally {
// If your thread needs special cleanup, this is the place to put it
// This block will be triggered by exceptions as well as breaks
}
}
You can check the interrupt flag for a thread using either interrupted() or isInterrupted(). The only real difference between them is that the former clears the interrupt status when it checks, while the latter does not. If you just want to make a one-off check and let the thread die, it does not really matter which one you use.
The advantage of this mechanism is that it gives you a lot more control than calling stop(), especially if your thread requires special cleanup.
I need a way to bind UI indicators to rapidly-changing values.
I have a class NumberCruncher which does a bunch of heavy processing in a critical non-UI thread, thousands of iterations of a loop per second, and some number of those result in changes to a set of parameters I care about. (think of them as a key-value store)
I want to display those at a slower rate in the UI thread; 10-20Hz would be fine. How can I add MVC-style notification so that my NumberCruncher code doesn't need to know about the UI code/binding?
The idiomatic way to do this is to use the SwingWorker class, and to use calls to publish(V...) to notify the Event Dispatch thread periodically causing it to update the UI.
In the below example taken from the Javadoc the number crunching takes place on a worker thread in the doInBackground() method, which calls publish on each iteration. This call causes the process(V...) method to be called asynchronously on the Event Dispatch thread allowing it to update the UI. Note that this ensures that the user interaface is always updated from the Event Dispatch thread. Also note that you may choose to call publish every N iterations to reduce the frequency at which the user interface is updated.
Example From Javadoc
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
#Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
}
return numbers;
}
#Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
SwingWorker, suggested by #Adamski, is preferable; but an instance of javax.swing.Timer is a convenient alternative for this, as "the action event handlers for Timers execute [on] the event-dispatching thread."
Seems like you might want to take the "Listener" approach. Allow your number cruncher to register listeners, then every 100-200 loops (configurable) (or on some change condition), notify the listeners that there is an update they should be aware of.
The listener can be another class that has a thread wait() ing on it, and when it gets notified, it just updates its internal variable, then notifies the waiting thread. The fast loop class then has a quick way to update an external value and not worry about access to its fast changing internal state.
The other thread that wait()s can also have a wait() on a timer thread that is set to 10-20HZ (configurable) to wait on the timer before wait()ing on the next update from your synchronized class.
Have a single object which your NumberCrucher modifies/keeps on changing based on the numerous operations you do. Let that run in a separate thread. Have a UI in swing which uses the same Object that NumberCruncher modifies. This thread is going to only read the values at specified time period so it should not be a problem of thread deadlocks.
NumberCruncher
public class NumberCruncher implements Runnable{
CommonObject commonObj;
public NumberCruncher(CommonObject commonObj){
this.commonObj = commonObj;
}
public void run() {
for(;;){
commonObj.freqChangeVal = Math.random();
}
}
}
CommonObject:
public class CommonObject {
public double freqChangeVal;
}
UI:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class UI extends JFrame implements Runnable{
private CommonObject commonObj = new CommonObject();
JLabel label ;
public static void main(String args[]){
UI ui = new UI();
ui.begin();
Thread t2 = new Thread(ui);
t2.start();
}
private void begin(){
JPanel panel = new JPanel();
label = new JLabel("Test");
panel.add(label);
Thread thread = new Thread(new NumberCruncher(commonObj));
thread.start();
this.add(panel);
this.setSize(200,200);
this.setVisible(true);
}
public void run() {
for(;;){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
label.setText(commonObj.freqChangeVal+"");
this.repaint();
}
}
}
In the Observer Design Pattern, the subject notifies all observers by calling the update() operation of each observer. One way of doing this is
void notify() {
for (observer: observers) {
observer.update(this);
}
}
But the problem here is each observer is updated in a sequence and update operation for an observer might not be called till all the observers before it is updated. If there is an observer that has an infinite loop for update then all the observer after it will never be notified.
Question:
Is there a way to get around this problem?
If so what would be a good example?
The problem is the infinite loop, not the one-after-the-other notifications.
If you wanted things to update concurrently, you'd need to fire things off on different threads - in which case, each listener would need to synchronize with the others in order to access the object that fired the event.
Complaining about one infinite loop stopping other updates from happening is like complaining that taking a lock and then going into an infinite loop stops others from accessing the locked object - the problem is the infinite loop, not the lock manager.
Classic design patterns do not involve parallelism and threading. You'd have to spawn N threads for the N observers. Be careful though since their interaction to this will have to be done in a thread safe manner.
You could make use of the java.utils.concurrent.Executors.newFixedThreadPool(int nThreads) method, then call the invokeAll method (could make use of the one with the timout too to avoid the infinite loop).
You would change your loop to add a class that is Callable that takes the "observer" and the "this" and then call the update method in the "call" method.
Take a look at this package for more info.
This is a quick and dirty implementation of what I was talking about:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main
{
private Main()
{
}
public static void main(final String[] argv)
{
final Watched watched;
final List<Watcher> watchers;
watched = new Watched();
watchers = makeWatchers(watched, 10);
watched.notifyWatchers(9);
}
private static List<Watcher> makeWatchers(final Watched watched,
final int count)
{
final List<Watcher> watchers;
watchers = new ArrayList<Watcher>(count);
for(int i = 0; i < count; i++)
{
final Watcher watcher;
watcher = new Watcher(i + 1);
watched.addWatcher(watcher);
watchers.add(watcher);
}
return (watchers);
}
}
class Watched
{
private final List<Watcher> watchers;
{
watchers = new ArrayList<Watcher>();
}
public void addWatcher(final Watcher watcher)
{
watchers.add(watcher);
}
public void notifyWatchers(final int seconds)
{
final List<Watcher> currentWatchers;
final List<WatcherCallable> callables;
final ExecutorService service;
currentWatchers = new CopyOnWriteArrayList<Watcher>(watchers);
callables = new ArrayList<WatcherCallable>(currentWatchers.size());
for(final Watcher watcher : currentWatchers)
{
final WatcherCallable callable;
callable = new WatcherCallable(watcher);
callables.add(callable);
}
service = Executors.newFixedThreadPool(callables.size());
try
{
final boolean value;
service.invokeAll(callables, seconds, TimeUnit.SECONDS);
value = service.awaitTermination(seconds, TimeUnit.SECONDS);
System.out.println("done: " + value);
}
catch (InterruptedException ex)
{
}
service.shutdown();
System.out.println("leaving");
}
private class WatcherCallable
implements Callable<Void>
{
private final Watcher watcher;
WatcherCallable(final Watcher w)
{
watcher = w;
}
public Void call()
{
watcher.update(Watched.this);
return (null);
}
}
}
class Watcher
{
private final int value;
Watcher(final int val)
{
value = val;
}
public void update(final Watched watched)
{
try
{
Thread.sleep(value * 1000);
}
catch (InterruptedException ex)
{
System.out.println(value + "interupted");
}
System.out.println(value + " done");
}
}
I'd be more concerned about the observer throwing an exception than about it looping indefinitely. Your current implementation would not notify the remaining observers in such an event.
1. Is there a way to get around this problem?
Yes, make sure the observer work fine and return in a timely fashion.
2. Can someone please explain it with an example.
Sure:
class ObserverImpl implements Observer {
public void update( Object state ) {
// remove the infinite loop.
//while( true ) {
// doSomething();
//}
// and use some kind of control:
int iterationControl = 100;
int currentIteration = 0;
while( curentIteration++ < iterationControl ) {
doSomething();
}
}
private void doSomething(){}
}
This one prevent from a given loop to go infinite ( if it makes sense, it should run at most 100 times )
Other mechanism is to start the new task in a second thread, but if it goes into an infinite loop it will eventually consume all the system memory:
class ObserverImpl implements Observer {
public void update( Object state ) {
new Thread( new Runnable(){
public void run() {
while( true ) {
doSomething();
}
}
}).start();
}
private void doSomething(){}
}
That will make the that observer instance to return immediately, but it will be only an illusion, what you have to actually do is to avoid the infinite loop.
Finally, if your observers work fine but you just want to notify them all sooner, you can take a look at this related question: Invoke a code after all mouse event listeners are executed..
All observers get notified, that's all the guarantee you get.
If you want to implement some fancy ordering, you can do that:
Connect just a single Observer;
have this primary Observer notify his friends in an order you define in code or by some other means.
That takes you away from the classic Observer pattern in that your listeners are hardwired, but if it's what you need... do it!
If you have an observer with an "infinite loop", it's no longer really the observer pattern.
You could fire a different thread to each observer, but the observers MUST be prohibited from changing the state on the observed object.
The simplest (and stupidest) method would simply be to take your example and make it threaded.
void notify() {
for (observer: observers) {
new Thread(){
public static void run() {
observer.update(this);
}
}.start();
}
}
(this was coded by hand, is untested and probably has a bug or five--and it's a bad idea anyway)
The problem with this is that it will make your machine chunky since it has to allocate a bunch of new threads at once.
So to fix the problem with all the treads starting at once, use a ThreadPoolExecutor because it will A) recycle threads, and B) can limit the max number of threads running.
This is not deterministic in your case of "Loop forever" since each forever loop will permanently eat one of the threads from your pool.
Your best bet is to not allow them to loop forever, or if they must, have them create their own thread.
If you have to support classes that can't change, but you can identify which will run quickly and which will run "Forever" (in computer terms I think that equates to more than a second or two) then you COULD use a loop like this:
void notify() {
for (observer: observers) {
if(willUpdateQuickly(observer))
observer.update(this);
else
new Thread(){
public static void run() {
observer.update(this);
}
}.start();
}
}
Hey, if it actually "Loops forever", will it consume a thread for every notification? It really sounds like you may have to spend some more time on your design.