Why stopping a SwingWorker does stop it immediately? - java

I'm using a SwingWorker to execute some repeatable tasks in background.
This is my Class:
public class CMyThread {
private SwingWorker<Object, Void> taskWorker;
public volatile boolean threadDone = false;
public CMyThread() {
}
#Override
public void stop() {
taskWorker.cancel(true);
}
#Override
public void start() {
taskWorker = new SwingWorker<Object, Void>() {
#Override
public Object doInBackground() {
while (!isCancelled()) {
// SOMETHING TIMECONSUMING THAT NEEDS TO BE DONE REPEATEDLY
CUtils.sleep(10000);
}
threadDone = true;
return null;
}
#Override
public void done() {
}
};
taskWorker.execute();
}
public void waitThreadToGentlyFinish() { // called when we call destroy() on the servlet
while (!threadDone) {
System.out.print("#");
CUtils.sleep(200);
}
}
}
And this is called this way:
CMyThread myThread = new CMyThread();
myThread.start();
Now, at one point I want to gently stop the thread.
So I call
myThread.stop();
myThread.waitThreadToGentlyFinish();
I'm expecting that the currently running [ACTION] is going to take time to finish, then only it will exit the loop and set the flag 'threadDone' to true. but what I actually see is that it exits the loop immediately and I never see any '#' characters displayed.
There is obviously something wrong in my code but I can't see the obvious.
Any idea guys ?

Related

Return value from Runnable

I have days trying to solve this but I can't, and the solution to this is to go to StackOverflow :D. Happens that I'm working with libgdx (library to make games) and to query code in Android is through the Handler class, running a Runnable and I don't really know how it works.
Basically what I want is to retrieve a value from Runnable. Using the Handler class with callbacks or something like that
I have to say that I don't really understand multithreading programming, and I saw several methods in Handler class, but I can't understand how it works (messaging, callbacks, etc.)
public class ActionResolverAndroid implements ActionResolver {
Handler handler;
Context context;
public ActionResolverAndroid(Context context) {
handler = new Handler();
this.context = context;
}
public boolean checkAndroidData(){
final boolean[] result = {false};
handler.post(new Runnable() {
#Override
public void run() {
// Android code here
// I need know the value of this variable
result[0] = true;
}
});
return result[0];
}
Thanks a lot for reading.
cheer
pd) I can't using Runnable .join() or Callable<>
When you post a Runnable to the Handler, that code will RUN in the MainThread (the one that you can touch your views).
doing:
public boolean checkAndroidData(){
final boolean[] result = {false};
handler.post(new Runnable() {
#Override
public void run() {
// Android code here
// I need know the value of this variable
result[0] = true;
}
});
return result[0];
}
Will make the result[0] being always false cause the Runnable would not runned yet.
The way you can notify yourself about the conclusion would be creating a Interface listener that you can notify when the Runnable ends.
Consider the following interface implementation:
public interface Listener<T> {
void on(T arg);
}
Working with a Listener would be waiting the response in the listener instead of the return value of a method, so the method above would be like:
public void checkAndroidData(Listener<Boolean> onCompleteListener){
handler.post(new Runnable() {
#Override
public void run() {
onCompleteListener.on(true);
}
});
}
And to call, you would pass a instance and wait for the response, like:
void onCreate(Bundle s){
super.onCreate(s);
checkAndroidData(new Listener<Boolean>(){
public void on(Boolean result){
Toast.makeText(result, Toast.LENGHT_LONG).show();
}
});
}
Well, this is a example, and in this case both code will run in the MainThread, this example doesnt cover multithreading, but about how to listen to the event that you started.
But the solution applies to multithreading if done in that context.
You can use a callback:
public interface RunnableListener
{
void onResult(boolean[] result);
}
// a field in your class
private RunnableListener runnableListener;
private void someMethod()
{
new Handler().post(new Runnable()
{
#Override public void run()
{
runnableListener.onResult(new boolean[]{true});
}
});
}

How can i know threads jobs are done?

In class B how can i know jobs of threads are finished? In after properties some worker are running. In class B, I need to know if worker are done?
public class A implements InitializingBean{
public void method1(){
...
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.print("test after properties set");
// send threads to executorService
ExecutorService executorService = Executors
.newFixedThreadPool(4);
for (int i = 0; i < 4; i++) {
Worker worker = new Worker();
executorService.submit(worker);
}
}
}
public class Worker implements Callable<Void>{
#Override
public void call(){
...
}
}
public class B{
public void methodB(){
A a = new A();
a.method1();
///Here How can i know the job of the workers are finished?
}
}
Use a listener/callback pattern to have the thread report completion to a listener. This simple example should show the process:
public interface ThreadCompleteListener {
void workComplete();
}
public class NotifyingThread extends Thread {
private Set<ThreadCompleteListener> listeners;
// setter method(s) for adding/removing listeners to go here
#Override
public void run() {
// do stuff
notifyListeners();
}
private void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.workComplete(); // notify the listening class
}
}
}
in your listening class:
NotifyingThread t = new NotifyingThread();
t.addListener(new ThreadCompleteListener() {
void workComplete() {
// do something
}
});
t.start();
You could use a Future implementation for your thread. It provides a Future#isDone()
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#isDone()
In general, it is usually more useful to be notified via a callback when jobs complete. However, since others have posted answers which follow that model, I'll instead post a solution that simply allows you to poll and ask whether the jobs are finished, in case this is what fits the needs of your application better.
public static interface InitializingBean{
public void afterPropertiesSet() throws Exception;
}
public static class A implements InitializingBean{
private List<Future<Void>> submittedJobs = Collections.synchronizedList(new ArrayList<Future<Void>>());
public void method1(){
//do stuff
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.print("test after properties set");
// send threads to executorService
ExecutorService executorService = Executors
.newFixedThreadPool(4);
synchronized (submittedJobs) {
for (int i = 0; i < 4; i++) {
Worker worker = new Worker();
submittedJobs.add(executorService.submit(worker));
}
}
}
/**
* Allows you to poll whether all jobs are finished or not.
* #return
*/
public boolean areAllJobsFinished(){
synchronized (submittedJobs) {
for(Future<Void> task : submittedJobs){
if(!task.isDone()){
return false;
}
}
return true;
}
}
}
public static class Worker implements Callable<Void>{
#Override
public Void call(){
//do worker job
return null; //to satisfy compiler that we're returning something.
}
}
public static class B{
public void methodB(){
A a = new A();
a.method1();
if(a.areAllJobsFinished()){
System.out.println("Congrats, everything is done!");
} else {
System.out.println("There's still some work being done :-(");
}
}
}
If you'd like to wait in that thread that starts the ExecutorService, you can actually use the awaitTermination method.
At the end of you afterPropertiesSet method, you should add:
executorService.shutdown();
After this you then add:
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)
This causes the thread to wait for all the executorService's tasks to be done and then continues. So place any code you want to execute after the call to awaitTermination.

Java Swingworker one after another and update GUI

I am working on java swing with some multithreaded application. The situation is so, that I need to execute one thread after another i.e I output of one is related to the second. I did the following.
// Class one
public class Samp implements Runnable{
public Samp(String name) {
this.setName = name;
}
public void run (){
// Here I have a file extraction method called
extract(this.getName);
}
// Extract Method
public Boolean extract(String filename){
// Some extraction Operation.
// I want to update the jTextField with the current filename under extraction.
}
}
// the GUI Class
public class Welcome extends javax.swing.JFrame {
SwingWorker<Boolean, Void>worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
Thread t1 = new Thread(new ZipUtility(fileName));
t1.start();
return true;
}
// Can safely update the GUI from this method.
#Override
protected void done() {
// Here when this worker is done I wanted to Run worker 2
}
};
SwingWorker<Boolean, Void>worker2 = .........
// Again when worker2 is done I wanted to run worker 3 and so on.
}
My Questions are :
1) How to run all the workers in a perfect sequencial order. i.e when worker1 is done then start worker 2, when worker2 is done then start worker 3 and so on.
2) How to update a textfield in my Welcome class, with the values from the Samp class.
Thanks in advance.
1) How to run all the workers in a perfect sequencial order. i.e when worker1 is done then start worker 2, when worker2 is done then start worker 3 and so on.
A little trick to remember, you can put a SwingWorker into a ExecutorService
So, using something like...
public static class Worker extends SwingWorker {
private int sequence;
public Worker(int sequence) {
this.sequence = sequence;
}
#Override
protected Object doInBackground() throws Exception {
System.out.println(sequence + "...");
Thread.sleep(500);
return null;
}
}
As a test, you could use something like...
ExecutorService es = Executors.newFixedThreadPool(1);
for (int index = 0; index < 10; index++) {
es.submit(new Worker(index));
}
es.shutdown();
(You don't need to call shutdown, but otherwise my tested never allowed the JVM to terminate ;))
Which will run the workers in the order they are submitted.
Now, if you want to feed the values from one SwingWorker to another, you could do something like...
public abstract class ChainedWorker<T, V> extends SwingWorker<T, V> {
private ChainedWorker<T, ?> next;
private T previousValue;
public ChainedWorker(ChainedWorker<T, ?> next) {
this.next = next;
}
public void setPreviousValue(T previousValue) {
this.previousValue = previousValue;
}
#Override
protected void done() {
try {
T previous = get();
if (next != null) {
next.setPreviousValue(previous);
next.execute();
}
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}
Which is simply a SwingWorker which allows you to provide a link in the chain (the next worker to call), which passes the value that this SwingWorker generated...or some such similar
Now, if you're really nuts and want to role your own, maybe something like...
public class ChainedWorkerBuilder {
private List<SwingWorker> workers;
private SwingWorker current;
public ChainedWorkerBuilder() {
workers = new ArrayList<>(25);
}
public ChainedWorkerBuilder add(SwingWorker worker) {
workers.add(worker);
return this;
}
public void execute() {
if (!workers.isEmpty()) {
SwingWorker worker = workers.remove(0);
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("state".equals(evt.getPropertyName())) {
SwingWorker source = (SwingWorker)evt.getSource();
switch (source.getState()) {
case DONE:
source.removePropertyChangeListener(this);
execute();
break;
}
}
}
});
}
}
}
2) How to update a textfield in my Welcome class, with the values from the Samp class.
I don't think I'm following your code directly, but, if you did something like...
SwingWorker<Boolean, Void>worker = new SwingWorker<Boolean, String>() {
protected Boolean doInBackground() throws Exception {
publish(fileName);
ZipUtility zu = new ZipUtility(fileName));
return zu.extract(fileName);
}
Then in the SwingWorkers process method you would be able to update the UI safely...
#Override
protected void process(List<String> chunks) {
// Grab the last element...
textfield.setText(chunks.get(chunks.size() - 1));
}
}
Simply call execute() on worker2 from worker1's done:
final SwingWorker<Boolean, Void> worker2 = new SwingWorker<Boolean, Void>() {
...
}
final SwingWorker<Boolean, Void> worker1 = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// Don't start a thread, do your work, otherwise the done will fire
// too early, also it's pointless to use worker and thread like that
return true;
}
// Can safely update the GUI from this method.
#Override
protected void done() {
// update some ui
// and start the second part
worker2.execute();
}
};

Stopping and resuming infinite loop on key input

Let's say we have an infinite loop, and we want to put it to sleep for a while, and then resume it. Instead of having a set time, we resume it when we press a key.
For example, in Java we could have:
while(true){
doSomething();
}
Now, we could make this interruptable in many ways. We want to interrupt it on a key press, so we will have:
boolean running = true;
...
this.addKeyListener(this);
...
#override
public void keyPressed(KeyEvent e){
running = false;
}
And then run a method (let's say run), which contains:
while(running){
doSomething();
}
But then we'd meet one problem: resuming.
So we take the keyPressed method, and change it's body to:
running = !running;
if(running){
run();
}
There is just one problem here: the KeyListener won't do anything until the run method is finished. I've tried using threads, where we would have:
private class Runner implements Runnable {
#Override
public void run() {
while (running) {
doSomething();
}
}
}
and in keyPressed:
if(running){
runner.wait();
}else{
runner.notify();
runner.run();
}
running = !running;
but in my actual code the doSomething method is code that can't be interrupted (because it handles output to the screen), so thread.wait() can never be called (it will throw exceptions all the time and not actually wait).
So then, to summarize: How does one stop and resume looping something at will using key input in Java?
wait and notify are intended to be called from different threads. As the name implies, wait should be called in the thread which is paused and waiting to be notified that a condition has changed:
private final Object keyPressMonitor = new Object();
private boolean running = true;
private Runnable gameLoop = new Runnable() {
#Override
public void run() {
try {
synchronized (keyPressMonitor) {
while (true) {
while (!running) {
keyPressMonitor.wait();
}
doSomething();
}
}
} catch (InterruptedException e) {
logger.log(Level.INFO,
"Interrupted; cleaning up and exiting.", e);
}
}
};
The other thread, presumably the AWT Event Dispatch Thread which is where your KeyListener (or Action invoked by an ActionMap/InputMap binding) is called, would notify the looping thread that the proper key has been pressed or released:
public void keyPressed(KeyEvent event) {
if (event.getKeyCode() == theKeyICareAbout) {
synchronized (keyPressMonitor) {
running = true;
keyPressMonitor.notifyAll();
}
}
}
public void keyReleased(KeyEvent event) {
if (event.getKeyCode() == theKeyICareAbout) {
synchronized (keyPressMonitor) {
running = false;
keyPressMonitor.notifyAll();
}
}
}
You can use Semaphore for these purposes:
private static class Runner implements Runnable {
private final AtomicInteger permits = new AtomicInteger(0);
private final Semaphore semaphore = new Semaphore(1, true);
private volatile boolean running;
public void putToSleep() {
semaphore.acquireUninterruptibly();
}
public void resume() {
semaphore.release(permits.getAndSet(0));
}
#Override
public void run() {
while (running) {
semaphore.acquireUninterruptibly(Integer.MAX_VALUE);
semaphore.release(Integer.MAX_VALUE);
doSomething();
}
}
private void doSomething() {
//...
}
}

AbstractQueuedSynchronizer.acquireShared waits infinitely even that waiting condition has changed

I wrote a simple class that uses AbstractQueuedSynchronizer. I wrote a class that represents a "Gate", that can be passed if open, or is blocking if closed. Here is the code:
public class GateBlocking {
final class Sync extends AbstractQueuedSynchronizer {
public Sync() {
setState(0);
}
#Override
protected int tryAcquireShared(int ignored) {
return getState() == 1 ? 1 : -1;
}
public void reset(int newState) {
setState(newState);
}
};
private Sync sync = new Sync();
public void open() {
sync.reset(1);
}
public void close() {
sync.reset(0);
}
public void pass() throws InterruptedException {
sync.acquireShared(1);
}
};
Unfortunately, if a thread blocks on pass method because gate is closed and some other thread opens the gate in meantime, the blocked one doesn't get interrupted - It blocks infinitely.
Here is a test that shows it:
public class GateBlockingTest {
#Test
public void parallelPassClosedAndOpenGate() throws Exception{
final GateBlocking g = new GateBlocking();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
g.open();
} catch (InterruptedException e) {
}
}
});
t.start();
g.pass();
}
}
Please help, what should I change to make the gate passing thread acquire the lock successfully.
It looks like setState() only changes the state, but doesn't notify blocked threads about the change.
Therefore you should use acquire/release methods instead:
#Override
protected boolean tryReleaseShared(int ignored) {
setState(1);
return true;
}
...
public void open() {
sync.releaseShared(1);
}
So, overall workflow of AbstractQueuedSynchronizer looks like follows:
Clients call public acquire/release methods
These methods arrange all synchronization functionality and delegate actual locking policy to protected try*() methods
You define your locking policy in protected try*() methods using getState()/setState()/compareAndSetState()

Categories

Resources