Java - SwingWorker - problem - java

I am developing a Java Desktop Application. This app executes the same task public class MyTask implements Callable<MyObject> { in multiple thread simultaneously.
Now, when a user clicks on a "start" button, I have created a SwingWorker myWorker and have executed it.
Now, this myWorker creates multiple instances of MyTask and submits them to an ExecutorService.
Each MyTask instance has a loop and generates an intermediate result at every iteration. Now, I want to collect these intermediate results from each MyTask instances as soon as they are generated. Then after collecting these intermediate results from every MyTask instance, I want to publish it through SwingWorker.publish(MyObject) so that the progress is shown on the EDT.
Q1. How can I implement this? Should I make MyTask subclass of SwingWorker instead of Callable to get intermediate results also, because I think that Callable only returns final result.
Q2. If the answer of Q1. is yes, then can you give me a small example to show how can I get those intermediate results and aggregate them and then publish them from main SwingWorker?
Q3. If I can't use SwingWorker in this situation, then how can I implement this?

Take a look at ExecutorCompletionService<T>. It's an Executor that supplies a take method to retrieve the result of any completed task.
Update:
Extending SwingWorker will not do what you want as it is specifically intended for offloading work from the EDT to a background thread. You can't use it to offload work from a background thread to other background threads. Calls to SwingWorker.publish result in the equivalent of a SwingUtilities.invokeLater. There is no mechanism I am aware of for doing the same thing from a background thread to a background thread. Your best bet is to create your MyTask with a reference to a Queue and have your SwingWorker.doInBackground poll the queue for intermediate results.

A1+A2.
Yatendra, is it necessary that your Main SwingWorker must be the only one that passes interim results to the EDT? If your tasks were also SwingWorker instances, the Main Worker could delegate the responsability of sending interim results back to the EDT to them and just take care of the TaskWorkers life-cycle.
package threading;
import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
class MainSwingWorker extends SwingWorker<Void, Void> {
private List<TaskWorker> tasks;
public MainSwingWorker() {
tasks = new LinkedList<TaskWorker>();
for(int i=0; i<2; i++)
tasks.add(new TaskWorker(i));
}
#Override
public Void doInBackground() throws Exception {
Test.log("Building tasks.");
for(TaskWorker task : tasks)
launch(task);
Test.log("Waiting 5 secs.");
Thread.sleep(5000);
Test.log("Cancelling tasks");
for(TaskWorker task : tasks )
task.cancel(true);
return null;
}
private void launch(final TaskWorker task) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test.log("Launching task worker.");
task.execute();
}
});
}
}
class TaskWorker extends SwingWorker<Void, String> {
private int id;
public TaskWorker(int wid) {
id = wid;
}
#Override
public Void doInBackground() throws Exception {
System.out.format("[%s] Starting worker %s\n", Thread.currentThread().getName(), id );
while( !isCancelled() ) {
// ***************************
// your task process code here
// ***************************
publish(String.format("A dummy interim result #%s", id));
Thread.sleep(1000);
}
return null;
}
#Override
public void process(List<String> results) {
// it's pretty obvious, that once this method gets called you can safely
// call the Swing API from EDT among with the interim results
for(String result : results )
Test.log(result);
}
}
public class Test {
public static void log(String msg) {
System.out.format("[%s] %s\n", Thread.currentThread().getName(), msg);
}
public static void main(String[] args) throws Exception {
log("Init.");
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
log("Starting main worker.");
MainSwingWorker worker = new MainSwingWorker();
worker.execute();
}
});
Thread.sleep(7000);
log("Finished.");
}
}
Keep mind that this is just a test, I know that there are a few ugly Thread.sleep(long) calls.
[main] Init.
[AWT-EventQueue-0] Starting main worker.
[SwingWorker-pool-1-thread-1] Building tasks.
[SwingWorker-pool-1-thread-1] Waiting 5 secs.
[AWT-EventQueue-0] Launching task worker.
[AWT-EventQueue-0] Launching task worker.
[SwingWorker-pool-1-thread-2] Starting worker 0
[SwingWorker-pool-1-thread-3] Starting worker 1
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[SwingWorker-pool-1-thread-1] Cancelling tasks
[main] Finished.
A3
But if having another ExecutorService to schedule your task execution is a requirement in your project, I would implement a similar publish-process mechanism to perform communication between your Main Swing Worker Thread and that Task Thread. Although it seems to be repetitive, You may use a java.concurrent.ConcurrentQueue to store interim results as they become available?
PS: I just noticed a few days ago, but there is an annoying bug around SwingWorkers that prevents its ExecutorService from caching unused threads.

A SwingWorker is also a Future. As such it has the get() method which can be used inside the done() method to get the result of doInBackground() when that method finishes.
Thus the construct becomes somewhat like:
SwingWorker<T,P> sw=new SwingWorker<T,P>() {
#Override
public T doInBackground() throws Exception {
T result;
// do stuff here
return result;
}
#Override
public void done() {
try {
T result=get();
// do stuff with result.
}
catch(ExecutionException e) {
Exception fromDoInBackground= (Exception) e.getCause();
// handle exception thrown from doInBackground()
}
catch(InterruptedException i) {
// handle the case in which a SwingWorker was cancelled. typically: do nothing.
}
}
};

Related

What are the thread command alternatives in Java?

I am dealing with threads and I want to run this code whenever I open Cal_JInternalFrame. It runs the fist time, but whenever I reopen the frame, it doesn't run again. I use t1.interrupted() at exit time of the whole application. The code is:
Thread t1 = new Thread( new Runnable() {
#Override
public void run() {
while ( !t1.isInterrupted() ) {
// ......... Oil Calculation Thread ...
int price = (Integer.parseInt(jLabel22.getText()));
int qty = (Integer)jSpinner8.getValue();
int totalOil =qty * price;
jTextField19.setText(String.valueOf(totalOil));
}
}
});
t1.start() is in the constructor of the main frame.
The thread primitive methods destroy(), stop(), resume(), and suspend() have been deprecated, so I can't use those. How can I stop and resume a thread now? And if my thread t1 is interrupted, how can it be resumed or run again?
Threads cannot be re-used. For tasks that require to be executed on a separate thread at different times, use a single thread executor.
It seems like you need a worker thread. Since standard threads are not reusable without extra work, we use worker threads to manage tasks that should be executed multiple times.
ExecutorService executors = Executors.newSingleThreadExecutor();
With this, you can reuse a single thread to execute code multiple times. It also allows you to make asynchronous callbacks using Future like this:
class Demo {
static ExecutorService executor = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
Future<String> result = executor.submit(new Callable<String>() {
public String call() {
//do something
return "Task Complete";
}
});
try {
System.out.println(result.get()); //get() blocks until call() returns with its value
}catch(Exception e) {
e.printStackTrace();
}
}
}
You can now re-use executor for the task that you want. It accepts Runnable through it's execute(Runnable) method.
I see you're using Swing. Post all swing code to the Event Dispatch Thread using EventQueue.invokeLater(Runnable). getText() and setText() should be called on the Event Dispatch Thread to avoid inconsistancies.
How can I stop and resume a thread now?
You can't. Instead, you need to make your thread stop and resume itself. For example:
private boolean wake;
public synchronized void wakeup() {
this.wake = true;
this.notify();
}
public void run() {
while ( !t1.isInterrupted() ) {
// do stuff ...
wake = false;
synchronized (this) {
while (!wake) {
try {
this.wait();
} catch (InterruptedException ex) {
t1.interrupt(); // reset the interrupted flag
}
}
}
}
}
When some other thread wants to get this one to do something, the calls the wakeup() method on the extended runnable object.
And if my thread t1 is interrupted, how can it be resumed or run again?
As you have written it, No. Once the thread returns from the run() method call, it cannot be restarted. You would need to create and start a brand new Thread.
However, what you are trying to do is unsafe. As #Erwin points out, it is not safe for the t1 thread to be calling methods on Swing objects such as jTextField19. You should only call methods on Swing objects from the Swing event dispatching thread.
Reference:
Concurrency in Swing

Capturing executor for current thread

I'm using ListenableFuture from Guava, and one nice thing about them is that one pass Executor to the Futures.addCallback method, that is, ask to execute the callback on a given thread/executor.
In my Android application, I want to be able to start the asynchronous execution based on ListenableFuture in the UI thread, and schedule a callback which is also executed also on the UI thread. Therefore, I'd like to somehow submit the UI thread executor to the Futures.addCallback method mentioned above. How to achieve that?
Or, in other words, I want to have an executor for the UI thread. Is it available already in Android, or, if I have to create my own, how do I do that?
EDIT: As an extension to this question, is it possible to do same thing, but not just with UI thread, but with any particular thread, where the call to async method is made?
I would be happy to know how to achieve the same effect without resorting to the Android-specific stuff like Handler and Looper, just with pure Java.
I think I've see some implementation doing that. The basic Idea is roughly
class UiThreadExecutor implements Executor {
private final Handler mHandler = new Handler(Looper.getMainLooper());
#Override
public void execute(Runnable command) {
mHandler.post(command);
}
}
You can delegate to run anything in the main thread by passing it to a handler for the main thread.
Edit: https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/android/MainThreadExecutor.java for example
Edit2: You can configure the handler like e.g. SensorManager#registerListener(..., Handler handler) allows you to do.
class HandlerThreadExecutor implements Executor {
private final Handler mHandler;
public HandlerThreadExecutor(Handler optionalHandler) {
mHandler = optionalHandler != null ? optionalHandler : new Handler(Looper.getMainLooper());
}
#Override
public void execute(Runnable command) {
mHandler.post(command);
}
}
The advantage over using the current thread's looper is that it makes it explicit which Looper you use. In your solution you take the Looper of whatever thread calls new ExecuteOnCaller() - and that's often not the thread you run code in later.
I would be happy to know how to achieve the same effect without resorting to the Android-specific stuff like Handler and Looper, just with pure Java.
Looper, Handler and the message queue behind all that logic are made of mostly pure Java. The problem with a generic solution is that you can't "inject" code to run into a thread. The thread must periodically check some kind of task queue to see if there is something to run.
If you write code like
new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
System.out.println("Hello");
}
}
}).start();
Then there is no way to make that thread do anything else but constantly print "Hello". If you could do that it would be like dynamically inserting a jump to other code into the program code. That would IMO be a terrible idea.
final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
Runnable codeToRunInThisThread = queue.take();
codeToRunInThisThread.run();
}
} catch (InterruptedException ignored) {}
}
}).start();
On the other hand is a simple thread that loops forever on a queue. The thread could do other tasks in between but you have to add a manual check into the code.
And you can send it tasks via
queue.put(new Runnable() {
#Override
public void run() {
System.out.println("Hello!");
}
});
There is no special handler defined here but that's the core of what Handler & Looper do in Android. Handler in Android allows you to define a callback for a Message instead of just a Runnable.
Executors.newCachedThreadPool() and similar do roughly the same thing. There are just multiple threads waiting on code in a single queue.
As an extension to this question, is it possible to do same thing, but not just with UI thread, but with any particular thread, where the call to async method is made?
The generic answer is No. Only if there is a way to inject code to run in that thread.
Based on asnwer from #zapl, here is my implementation, which also answers the edited (extended) question: https://gist.github.com/RomanIakovlev/8540439
Figured out I'll also put it here, in case if link will rot some day:
package com.example.concurrent;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
* When the calling thread has a Looper installed (like the UI thread), an instance of ExecuteOnCaller will submit
* Runnables into the caller thread. Otherwise it will submit the Runnables to the UI thread.
*/
public class ExecuteOnCaller implements Executor {
private static ThreadLocal<Handler> threadLocalHandler = new ThreadLocal<Handler>() {
#Override
protected Handler initialValue() {
Looper looper = Looper.myLooper();
if (looper == null)
looper = Looper.getMainLooper();
return new Handler(looper);
}
};
private final Handler handler = threadLocalHandler.get();
#Override
public void execute(Runnable command) {
handler.post(command);
}
}
My pattern to use it would be like this:
/**
* in SomeActivity.java or SomeFragment.java
*/
Futures.addCallback(myModel.asyncOperation(param), new FutureCallback<Void>() {
#Override
public void onSuccess(Void aVoid) {
// handle success
}
#Override
public void onFailure(Throwable throwable) {
// handle exception
}
}, new ExecuteOnCaller());
Use com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD.
An Executor that uses the main application thread.
Source: Android docs
The tasks APIs are part of Google Play services since version 9.0.0.
For Android UI thread executor use:
ContextCompat.getMainExecutor(context)
To address your question and extended question to create an Executor that simply runs on the current thread and avoids Android classes:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
See documentation: https://developer.android.com/reference/java/util/concurrent/Executor

Using Guava's EventBus, possible to run subscriber code on thread that created the bus?

Using Guava's EventBus, I want to be able to post from a background thread (called "background") to a specific thread (in this case, thread "main") that updates the UI. I thought the following would work, but this calls the subscriber code from the background thread:
package com.example;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EventBusTester {
private static final Logger log = LoggerFactory.getLogger(EventBusTester.class);
public static void main(String... args) {
new EventBusTester().run();
}
private void run() {
log.info("Starting on thread {}.", Thread.currentThread().getName());
final EventBus eventBus = new AsyncEventBus(MoreExecutors.sameThreadExecutor());
eventBus.register(this);
Thread background = new Thread(new Runnable() {
#Override
public void run() {
long now = System.currentTimeMillis();
eventBus.post(now);
log.info("Posted {} to UI on thread {}.", now, Thread.currentThread().getName());
}
}, "background");
background.start();
}
#Subscribe
public void updateUi(Long timestamp) {
log.info("Received {} on UI on thread {}.", timestamp, Thread.currentThread().getName());
}
}
This prints the following:
02:20:43.519 [main] INFO com.example.EventBusTester - Starting on thread main.
02:20:43.680 [background] INFO com.example.EventBusTester - Received 1387848043678 on UI on thread background.
02:20:43.680 [background] INFO com.example.EventBusTester - Posted 1387848043678 to UI on thread background.
So my questions are:
Is it possible to do what I want, e.g. with an ExecutorService I've somehow missed, or writing a custom ExecutorService, or
Do I need some other library to accomplish this? E.g. Square's Otto (because I'll be using this on Android as well).
I'd rather stay with pure Guava, though.
Thanks!
If you use an EventBus instance then the #Subscribe method will be executed on the same thread that posted the event.
If you want to do something different then use an AsyncEventBus where you can provide an Executor to define the exact behavior in case of an event gets posted.
For instance, on Android to make every #Subscribe method run on the main thread you can do the following:
EventBus eventBus = new AsyncEventBus(new Executor() {
private Handler mHandler;
#Override
public void execute(Runnable command) {
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
}
mHandler.post(command);
}
});
The Looper.getMainLooper() returns the application's main looper, which lives on the main thread of the application.
In UI applications, there is a thread running an event dispatch loop. which is processing user input events and calling handlers. Typically, UI framework provides some way to execute your code in this thread, like SwingUtilities.invokeLater(Runnable)
AsyncEventBus allows you to pass pass Executor, which will be calling UI-framework specific function for that.
There are a few questions here related to executing UI code from a worker thread on android.

Java: Creating a multi threaded reader

I'm creating a reader application. The reader identifies based on the parameters which file to read, does some processing and returns the result to the caller.
I am trying to make this multi-threaded, so that multiple requests can be processed. I thought it was simple but later realized it has some complexity. Even though i create threads using executor service, I still need to return the results back to the caller. So this means waiting for the thread to execute.
Only way i can think of is write to some common location or db and let the caller pick the result from there. Is there any approach possible?
Maybe an ExecutorCompletionService can help you. The submitted tasks are placed on a queue when completed. You can use the methods take or poll depending on if you want to wait or not for a task to be available on the completion queue.
ExecutorCompletionService javadoc
Use an ExecutorService with a thread pool of size > 1, post custom FutureTask derivatives which override the done() method to signal completion of the task to the UI:
public class MyTask extends FutureTask<MyModel> {
private final MyUI ui;
public MyTask(MyUI toUpdateWhenDone, Callable<MyModel> taskToRun) {
super(taskToRun);
ui=toUpdateWhenDone;
}
#Override
protected void done() {
try {
// retrieve computed result
final MyModel computed=get();
// trigger an UI update with the new model
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ui.setModel(computed); // set the new UI model
}
});
}
catch(InterruptedException canceled) {
// task was canceled ... handle this case here
}
catch(TimeoutException timeout) {
// task timed out (if there are any such constraints).
// will not happen if there are no constraints on when the task must complete
}
catch(ExecutionException error) {
// handle exceptions thrown during computation of the MyModel object...
// happens if the callable passed during construction of the task throws an
// exception when it's call() method is invoked.
}
}
}
EDIT: For more complex tasks which need to signal status updates, it may be a good idea to create custom SwingWorker derivatives in this manner and post those on the ExecutorService. (You should for the time being not attempt to run multiple SwingWorkers concurrently as the current SwingWorker implementation effectively does not permit it.)

JDK-7 SwingWorker deadlocks?

I have a small image processing application which does multiple things at once using SwingWorker. However, if I run the following code (oversimplified excerpt), it just hangs on JDK 7 b70 (windows) but works in 6u16. It starts a new worker within another worker and waits for its result (the real app runs multiple sub-workers and waits for all this way). Did I use some wrong patterns here (as mostly there is 3-5 workers in the swingworker-pool, which has limit of 10 I think)?
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Swing {
static SwingWorker<String, Void> getWorker2() {
return new SwingWorker<String, Void>() {
#Override
protected String doInBackground() throws Exception {
return "Hello World";
}
};
}
static void runWorker() {
SwingWorker<String, Void> worker
= new SwingWorker<String, Void>() {
#Override
protected String doInBackground() throws Exception {
SwingWorker<String, Void> sw2 = getWorker2();
sw2.execute();
return sw2.get();
}
};
worker.execute();
try {
System.out.println(worker.get());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runWorker();
}
});
}
}
As nobody has fired off the link yet, it seems this is actually a known bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6880336
Surprisingly there are less than 100 votes for what should be a showstopper bug for most non-trivial applications.
Your SwingWorkers are executed in your SwingWorker Thread. So when you see
It seems it hangs on sw2.get() and there is only one swingworker- named thread in jdk7. On jdk6, I see 3-5 at once. – kd304
This is because the SwingWorker class is not a thread, but a task to be run on a thread, and the default configuration for the ExecutorService for SwingWorker in Java 6 is configured different from the one in Java 7. IE your SwingWorkerExecutorService (which is defined inside the SwingWorker class) has a different value for the max number of Threads to allocate to the tasks.
//From Java 6 SwingWorker
private static final int MAX_WORKER_THREADS = 10;
public final void execute() {
getWorkersExecutorService().execute(this);
}
private static synchronized ExecutorService getWorkersExecutorService() {
...
private static synchronized ExecutorService getWorkersExecutorService() {
new ThreadPoolExecutor(0, MAX_WORKER_THREADS,
1L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory)
}
You only have the one thread running the SwingWorker tasks, and that first task is waiting for the completion of the second task, which can't be run, because the Thread the second task would be run on is waiting for the second task to complete before it will return. Making on swingworker thread dependent on the execution of another is a sure path to deadlock. You may want to look at using an ExecutorService to schedule events to be run on the SwingWorker Thread, and don't make one scheduled event dependent on another scheduled event's completion.
Java 7 SwingWorker
Looking at the source code for SwingWorker, it looks like an ExecutorService is being used as a pool of worker threads. It's possible that the type of ExecutorService used has changed between Java 6 and Java 7. It looks like your code will deadlock if the ExecutorService only manages exactly 1 thread at a time (as you seem to have noticed).
This is because your 'sw2.get()' call will block the current thread, which is the same thread the sw2 will try to use. sw2 can never execute because the first worker is blocking.
I think the best solution is to change your logic so that you don't call chains of Swing workers like this.
Before JDK update 18 you could run:
public static void main(String[] args) {
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
System.out.println("ok");
return null;
}
}.execute();
}
This code doesn't work anymore, simply because SwingWorkers must be executed on EDT.
Therefore, you can't nest SwingWorkers (sw2 will never run in you sample code in newer JDKs).
I guess replacing nested swingWorkers with executorService java.util.concurrent.Future calls is a good workaround.

Categories

Resources