How can I enable to stop MY running code? - java

I have a long operation running in the background, like uploading stuff, converting images, audio, video, etc.
I would like to stop/cancel them if the user requested to stop the operation altogether.
How can accomplish this? Is there a design pattern for this?
Note: Some of the running code can be canceled and some can't. How do I find a compromise around that?
EDIT: I should have said that I want the operation to stop immediately.

To summarize and extend on what Jon has said:
You should let the thread know that it should exit the loop (volatile flag).
You may interrupt() the thread if you want it to exit out of a blocking state.
You should handle the InterruptedException inside the run method.
You should exit gracefully when you're interrupted (i.e. finish up whatever you're doing and clean up).
Some code:
private volatile bool _running;// volatile guarantees that the flag will not be cached
public void kill(){_running = false;}
public void run()
{
while(_running)
{
try
{
DoWork(); // you may need to synchronize here
}
catch(InterruptedException e)
{
// Handle e
}
}
}

(I'm assuming you're already performing the background work in a separate thread.)
Basically, you keep a shared boolean flag which the UI thread can set and the background thread periodically reads. When the flag says "stop", you stop :)
Note that the flag should be volatile or you should use a lock in order to make sure that the background thread definitely "sees" a change written from the UI thread.
It's relatively crude and feels a bit "manual" but it means you don't risk instability through aborting half way through an operation, unlike approaches such as Thread.stop().

My 2 cents. A task that is cancelable. The cancelImpl() and runImpl() need to be implemented.
import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class CancelableTask extends Observable<CancelableTask>
implements Runnable {
private volatile boolean isStarted = false;
private volatile boolean isCanceled = false;
private volatile boolean isSuccess = false;
private volatile Exception e;
private volatile AtomicBoolean doneLock = new AtomicBoolean(false);
protected final AtomicInteger progress = new AtomicInteger(0);
public CancelableTask() {
}
#Override
public final void run() {
try {
runUnsafe();
} catch (Exception e) {
Config.getLog().i("CancelableTask threw an exception", e);
}
}
public final void runUnsafe() throws Exception {
// Config.getLog().d("Running cancelable task: " + toString());
notifyObservers(this);
isStarted = true;
try {
if (!isCanceled) {
runImpl();
}
} catch (Exception e) {
// Note: Cancel may throw exception
if (doneLock.compareAndSet(false, true)) {
this.e = e;
notifyObservers(this);
clearObservers();
// Someone else should do something with the exception
// Config.getLog().i("Failed cancelable task: " + toString(), e);
throw e;
}
// Cancel got to the lock first but may NOT have yet changed the cancel flag.
// Must throw cancellation exception.
}
if (doneLock.compareAndSet(false, true)) {
isSuccess = true;
progress.set(100);
notifyObservers(this);
clearObservers();
// Config.getLog().d("Finished cancelable task: " + toString());
return;
}
// The task was canceled but the isCanceled may not have been set yet.
synchronized (doneLock) { // Waiting for the cancel to finish it's logic
}
// assert isCanceled; // Commented out because android crashes the app in assertion
// No need to notify here because cancel was already notified in
// cancel method.
// notifyObservers(this);
// Config.getLog().d("Already canceled task: " + toString());
throw new CancellationException("Canceled while running!");
}
protected abstract void runImpl() throws Exception;
protected void cancelImpl() {}
public final void cancel() {
synchronized (doneLock) {
if (doneLock.compareAndSet(false, true)) {
// Config.getLog().i("Canceling cancelable task: " + toString());
isCanceled = true;
cancelImpl();
notifyObservers(this);
clearObservers();
}
}
}
public final boolean isCanceled() {
return isCanceled;
}
public final boolean isSuccessful() {
return isSuccess;
}
public final boolean isDone() {
return doneLock.get();
}
public final boolean isStarted() {
return isStarted;
}
public final Exception getError() {
return e;
}
public int getProgress() {
return progress.get();
}
/**
* Observers will be cleared after the task is done but only after all of them are notified.
*/
#Override
public void addObserver(Observer<CancelableTask> observer) {
super.addObserver(observer);
}
// protected void incrementProgress(int value) {
// progress += value;
// }
}
There is the CancelableCollection as well:
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.concurrent.CancellationException;
public class CancelableCollection extends CancelableTask {
private LinkedHashMap<CancelableTask, Integer> cancelables = new LinkedHashMap<CancelableTask, Integer>();
private volatile boolean normalizing;
private volatile State state = new State(null, 0, 0);
private boolean isOneFailsAll = true;
// public boolean isOneFailsAll() {
// return isOneFailsAll;
// }
public void setOneFailsAll(boolean isOneFailsAll) {
this.isOneFailsAll = isOneFailsAll;
}
public int getTotalWeight() {
Collection<Integer> values = cancelables.values();
int total = 0;
for (int weight : values) {
total += weight;
}
return total;
}
/**
* Adds and runs the cancelable
*
* #param cancelable
* #return
* #throws Exception
* if failed while running
* #throws CancellationException
* if already canceled
*/
public void add(CancelableTask cancelable, int relativeTime) {
if (cancelable == null) {
return;
}
cancelables.put(cancelable, relativeTime);
if (isCanceled()) {
throw new CancellationException("Canceled while running!");
}
if (isDone()) {
throw new RuntimeException(
"Cannot add tasks if the Cancelable collection is done running");
}
if (normalizing) {
throw new RuntimeException(
"Cannot add tasks if already started normalizing");
}
}
#Override
protected void runImpl() throws Exception {
normalizeProgress();
for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
int currentRelativeTime = entry.getValue();
CancelableTask currentTask = entry.getKey();
// Advance the state to the next one with the progress from the
// previous one.
state = new State(currentTask, currentRelativeTime, state.getProgress());
try {
currentTask.runUnsafe();
} catch (Exception e) {
if (isOneFailsAll) {
throw e;
}
Config.getLog().i("Task failed but continueing with other tasks", e);
}
}
state = new State(null, 0, 100);
}
private void normalizeProgress() {
normalizing = true;
int overall = 0;
for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
overall += entry.getValue();
}
double factor = overall == 0 ? 1 : (double)100 / overall;
for (Entry<CancelableTask, Integer> entry : cancelables.entrySet()) {
entry.setValue((int) (entry.getValue() * factor));
}
}
#Override
protected void cancelImpl() {
for (CancelableTask cancelable : cancelables.keySet()) {
cancelable.cancel();
}
}
#Override
public int getProgress() {
int progress = this.progress.get();
int stateProgress = state.getProgress();
this.progress.compareAndSet(progress, stateProgress); // Setting this value just for easier debugging. I has no meaning in CancelableCollection
return super.getProgress();
}
private static class State {
private CancelableTask currentTask;
private int currentRelativeTime;
private int progress;
public State(CancelableTask currentTask, int currentRelativeTime,
int progress) {
super();
this.currentTask = currentTask;
this.currentRelativeTime = currentRelativeTime;
this.progress = progress;
}
public int getProgress() {
return progress
+ (currentTask == null ? 0 : (int)(currentTask.getProgress()
* (double)currentRelativeTime / 100));
}
}
}

stop the thread or asynctask youre using or call this.finish

Related

Pause and resume threads in ThreadPool [duplicate]

I submitted bunch of jobs to an executorservice in Java and I somehow want to temporarily pause all these jobs. What's the best way to do this? How can I resume? Or am I doing this completely wrong? Should I follow some other pattern for what I want to achieve (i.e. ability to pause/resume execution services)?
To answer my own question, I found an example of a PausableThreadPoolExecutor in the javadocs of ThreadPoolExecutor itself. Here is my version using Guava's Monitors:
import com.google.common.util.concurrent.Monitor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
public class PausableExecutor extends ScheduledThreadPoolExecutor {
private boolean isPaused;
private final Monitor monitor = new Monitor();
private final Monitor.Guard paused = new Monitor.Guard(monitor) {
#Override
public boolean isSatisfied() {
return isPaused;
}
};
private final Monitor.Guard notPaused = new Monitor.Guard(monitor) {
#Override
public boolean isSatisfied() {
return !isPaused;
}
};
public PausableExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, threadFactory);
}
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
monitor.enterWhenUninterruptibly(notPaused);
try {
monitor.waitForUninterruptibly(notPaused);
} finally {
monitor.leave();
}
}
public void pause() {
monitor.enterIf(notPaused);
try {
isPaused = true;
} finally {
monitor.leave();
}
}
public void resume() {
monitor.enterIf(paused);
try {
isPaused = false;
} finally {
monitor.leave();
}
}
}
I made some criticisms on your accepted answer, but they weren't very constructive... So here's my solution. I would use a class like this one and then call checkIn wherever/whenever I want pause functionality. Find it on GitHub!
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Provides a mechanism to pause multiple threads.
* If wish your thread to participate, then it must regularly check in with an instance of this object.
*
* #author Corin Lawson <corin#phiware.com.au>
*/
public class Continue {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
public void checkIn() throws InterruptedException {
if (isPaused) {
pauseLock.lock();
try {
while (isPaused)
unpaused.await();
} finally {
pauseLock.unlock();
}
}
}
public void checkInUntil(Date deadline) throws InterruptedException {
if (isPaused) {
pauseLock.lock();
try {
while (isPaused)
unpaused.awaitUntil(deadline);
} finally {
pauseLock.unlock();
}
}
}
public void checkIn(long nanosTimeout) throws InterruptedException {
if (isPaused) {
pauseLock.lock();
try {
while (isPaused)
unpaused.awaitNanos(nanosTimeout);
} finally {
pauseLock.unlock();
}
}
}
public void checkIn(long time, TimeUnit unit) throws InterruptedException {
if (isPaused) {
pauseLock.lock();
try {
while (isPaused)
unpaused.await(time, unit);
} finally {
pauseLock.unlock();
}
}
}
public void checkInUninterruptibly() {
if (isPaused) {
pauseLock.lock();
try {
while (isPaused)
unpaused.awaitUninterruptibly();
} finally {
pauseLock.unlock();
}
}
}
public boolean isPaused() {
return isPaused;
}
public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}
public void resume() {
pauseLock.lock();
try {
if (isPaused) {
isPaused = false;
unpaused.signalAll();
}
} finally {
pauseLock.unlock();
}
}
}
For example:
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
public class PausableExecutor extends ScheduledThreadPoolExecutor {
private Continue cont;
public PausableExecutor(int corePoolSize, ThreadFactory threadFactory, Continue c) {
super(corePoolSize, threadFactory);
cont = c;
}
protected void beforeExecute(Thread t, Runnable r) {
cont.checkIn();
super.beforeExecute(t, r);
}
}
This has the added benefit that you can pause many threads with a single call to Continue's pause.
I was looking for pause/resume functionality in executor, but with additional ability to await for any currently being processed tasks. Below is variant of other great implementations from this SO with addition of await functions. I was testing it on executor with single thread. So basic usage is:
executor.pause();
executor.await(10000); // blocks till current tasks processing ends
class code:
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PausableScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
public boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
private Latch activeTasksLatch = new Latch();
private class Latch {
private final Object synchObj = new Object();
private int count;
public boolean awaitZero(long waitMS) throws InterruptedException {
long startTime = System.currentTimeMillis();
synchronized (synchObj) {
while (count > 0) {
if ( waitMS != 0) {
synchObj.wait(waitMS);
long curTime = System.currentTimeMillis();
if ( (curTime - startTime) > waitMS ) {
return count <= 0;
}
}
else
synchObj.wait();
}
return count <= 0;
}
}
public void countDown() {
synchronized (synchObj) {
if (--count <= 0) {
// assert count >= 0;
synchObj.notifyAll();
}
}
}
public void countUp() {
synchronized (synchObj) {
count++;
}
}
}
/**
* Default constructor for a simple fixed threadpool
*/
public PausableScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize);
}
/**
* Executed before a task is assigned to a thread.
*/
#Override
protected void beforeExecute(Thread t, Runnable r) {
pauseLock.lock();
try {
while (isPaused)
unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
activeTasksLatch.countUp();
super.beforeExecute(t, r);
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
try {
super.afterExecute(r, t);
}
finally {
activeTasksLatch.countDown();
}
}
/**
* Pause the threadpool. Running tasks will continue running, but new tasks
* will not start untill the threadpool is resumed.
*/
public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}
/**
* Wait for all active tasks to end.
*/
public boolean await(long timeoutMS) {
// assert isPaused;
try {
return activeTasksLatch.awaitZero(timeoutMS);
} catch (InterruptedException e) {
// log e, or rethrow maybe
}
return false;
}
/**
* Resume the threadpool.
*/
public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}
The problem is that the Runnable/Callable themselves need to check when to pause/resume. That being said there and many ways to do this, and it depends on your requirements on how best to do this. Whatever your solution you need to make the waiting interruptable, so the thread can be shutdown cleanly.
I know this is old, but I tried all of these answers and none of them worked for what I was trying to do with a pausable timer; they all would throw out all of the data it would have been doing on a schedule as soon as it resumed (all at once).
Instead I found this Timer class on GitHub* here. This worked really well for me.
*I did not write this code, just found it.

how to graceful stop java threads in sequence?

I have started threads in sequence but i don't know how to stop them in reverse sequence.
For example:
they are starting like this: A->B->C->D
and I want them to stop: D->C->B->A
I don't know how to stop threads at all and not even in this order.
I appreciate any help or advice.
import java.util.*;
class Service extends Thread
{
private RobotController controller;
private String robotID;
private byte[] lock;
public Service(RobotController cntrl, String id)
{
controller = cntrl;
robotID = id;
}
public byte[] getLock() { return lock;}
public void run()
{
lock = new byte[0];
synchronized(lock)
{
byte[] data;
while ((data = controller.getData()) == null)
{
try {
lock.wait();
} catch (InterruptedException ie) {}
}
System.out.println("Robot " + robotID + " Working");
}
}
}
class RobotController
{
private byte[] robotData;
private Vector threadList = new Vector();
private Service thread_A;
private Service thread_B;
private Service thread_C;
private Service thread_D;
private volatile boolean done;
public void setup(){
thread_A = new Service(this, "A");
thread_B = new Service(this, "B");
thread_C = new Service(this, "C");
thread_D = new Service(this, "D");
threadList.addElement(thread_A);
threadList.addElement(thread_B);
threadList.addElement(thread_C);
threadList.addElement(thread_D);
thread_A.start();
thread_B.start();
thread_C.start();
thread_D.start();
start();
stop();
}
public void start()
{
System.out.println("Thread starts");
{
for (int i=0; i <= 3; i++)
{
try {
Thread.sleep(500);
}catch (InterruptedException ie){}
putData(new byte[10]);
Service rbot = (Service)threadList.elementAt(i);
byte[] robotLock = rbot.getLock();
synchronized(robotLock) {
robotLock.notify();
}
}
}
}
public void stop()
{
{
}
}
public synchronized byte[] getData()
{
if (robotData != null)
{
byte[] d = new byte[robotData.length];
System.arraycopy(robotData, 0, d, 0, robotData.length);
robotData = null;
return d;
}
return null;
}
public void putData(byte[] d) { robotData = d;}
public static void main(String args[])
{
RobotController controller = new RobotController();
controller.setup();
}
}
I'll usually include something like a cancel() method in my threads if I want to explicitly terminate them.
class Service extends Thread {
private volatile boolean cancel = false;
public void cancel() {
cancel = true;
}
public void run() {
...
while (!cancel && (data = controller.getData()) == null) {
...
}
}
}
Keep your threads in a stack as mre suggests, then pop through the stack and call cancel and then interrupt on each thread.
I have started threads in sequence but i don't know how to stop them in reverse sequence.
This is difficult to do. There are ways you can stop a thread either by setting a volatile shutdown boolean or interrupting them, but none of these mechanisms are guaranteed to stop a thread immediately.
You certainly can keep a List<Thread> when you build them, call Collections.reverse(threadList) and then call thread.interrupt() on each one in turn. If you must have them finish in order then you should interrupt() them and then join them. Something like:
Collections.reverse(threadList);
for (Thread thread : threadList) {
thread.interrupt();
thread.join();
}
Then each thread should be doing something like:
while (!Thread.currentThread().isInterrupted()) {
...
}
Note that if you are running Thread.sleep(...) or other methods that throw InterruptedException, you'll need to re-enable the interrupt flag:
try {
Thread.sleep(...);
} catch (InterruptedException e) {
// by convention if InterruptedException thrown, interrupt flag is cleared
Thread.currentThread().interrupt();
...
}
Have each thread keep a reference to the next thread to be started. Then each thread can periodically check to see if the thread is still alive. If not, that thread should terminate. When it does, the previous thread will notice and terminate, and so on up the chain.
abstract class ChainThread extends Thread {
private final Thread next;
ChainThread(Thread next) { this.next = next; }
#Override
public final void run() {
next.start();
while (!Thread.currentThread().isInterrupted() && next.isAlive()) {
do();
}
}
abstract void do();
}
If I read the Service code correctly, it waits until there's data to execute on, then finishes. So you don't really need an explicit stop or cancel type signal, the threads will terminate themselves after they do work.
To enforce ordering of shutdown, you could make each Service aware of the previous Service, and then call previousService.join(). Assuming no InterruptedExceptions are thrown, they will then shutdown in order after seeing that the controller has data.
Create the Services this way:
Service serviceA = new Service(controller, "A", null);
Service serviceB = new Service(controller, "B", serviceA);
Service serviceC = new Service(controller, "C", serviceB);
Service serviceD = new Service(controller, "D", serviceC);
and the implementation is edited to exit only after dependent Services are complete:
private final RobotController controller;
private final String robotID;
private byte[] lock;
private final Service dependentService;
public Service(RobotController cntrl, String id, Service dependentService) {
controller = cntrl;
robotID = id;
this.dependentService = dependentService;
}
public byte[] getLock() {
return lock;
}
#Override
public void run() {
lock = new byte[0];
synchronized (lock) {
byte[] data;
while ((data = controller.getData()) == null) {
try {
lock.wait();
}
catch (InterruptedException ie) {
}
}
System.out.println("Robot " + robotID + " Working");
}
if (dependentService != null) {
try {
dependentService.join();
}
catch (InterruptedException e) {
this.interrupt();
}
}
}

Thread Wait and Wake up

I'm trying to simulate a simple thermostat, using multi-threading. The thermostat should increase the temperature in order to reach the value that the user requested for which is "Max" value in the code below. I have two thread, one in charge of increasing the temperature and the other for decreasing it. but the condition for decreasing is it should be only running when the gas is off.
but I have a problem with implementing this concept. as the code below runs, the second thread keeps throwing exception of null!
<pre><code>`private void formWindowActivated(java.awt.event.WindowEvent evt) {
systemInitial();
Thread temperatureUp = new Thread()
{
#Override
public void run()
{
while(true)
{
Max = Integer.parseInt(lblDesiredTemp.getText());
Current = Integer.parseInt(lblCurrentTemp.getText());
try
{
if(Max>Current)
{
lblGasStatus.setText("On");
lblTemperatureSensor.setText("increasing");
increaseTemeture();
}
else
{
lblGasStatus.setText("Off");
if(Current != 0)
lblTemperatureSensor.setText("decreasing");
else
lblTemperatureSensor.setText("----");
}
}
catch(Exception ex)
{
txtLog.setText(ex.getMessage() + "\n" + txtLog.getText() );
}
}
}
};
Thread systemUpdater = new Thread()
{
#Override
public void run()
{
while(true)
{
try
{
notifyGasBoiler(this);
if(Current>0)
decreaseTemeture();
}
catch(Exception ex)
{
txtLog.setText(ex.getMessage() + "\n" + txtLog.getText() );
}
}
}
};
temperatureUp.start();
systemUpdater.start();
}
private synchronized void notifyGasBoiler(Thread gasOff) throws InterruptedException
{
try
{
if("On".equals(lblGasStatus.getText()))
{
gasOff.wait();
txtLog.setText(txtLog.getText() + "\n" + gasOff.getName() + " waits.");
}
else
notifyAll();
}
catch (Exception ex)
{
txtLog.setText(ex.getMessage() + "\n" + txtLog.getText() );
}
}`
what am I missing here?
UPDATE I:
this is the log I'm getting by running the system and request the 2 temperature:
Temperature increased to 1
Temperature increased to 2
null
null
null
....
UPDATE II:
I used printStackTrace for exception and it got me this:
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at sol.smarthome.GUI.notifyGasBoiler(GUI.java:300)
at sol.smarthome.GUI.access$900(GUI.java:14)
at sol.smarthome.GUI$5.run(GUI.java:276)
Update III
<pre><code>`private void btnUpActionPerformed(java.awt.event.ActionEvent evt) {
if(Max<=8)
{
Max++;
String strI = String.valueOf(Max);
lblDesiredTemp.setText(strI);
setGasBoilerStatus();
}
}
private void btnDownActionPerformed(java.awt.event.ActionEvent evt) {
if(Max>0)
{
Max--;
String strI = String.valueOf(Max);
lblDesiredTemp.setText(strI);
setGasBoilerStatus();
}
}
private void formWindowActivated(java.awt.event.WindowEvent evt) {
systemInitial();
tempUp = new temperatureUp();
tempDown = new temperatureDown();
tempUp.start();
tempDown.start();
}
private synchronized void increaseTemeture() throws InterruptedException
{
synchronized (monitor) {
if (!getBoilerStatus())
{
tempUp.wait();
//return;
}
else
{
Max = Integer.parseInt(lblDesiredTemp.getText());
Current = Integer.parseInt(lblCurrentTemp.getText());
if(Max>Current)
{
lblGasStatus.setText("On");
lblTemperatureSensor.setText("increasing");
Thread.sleep(4000);
Current ++;
lblPumpStatus.setText("On");
lblCurrentTemp.setText(String.valueOf(Current));
txtLog.setText("Temperature increased to " + Current + "\n"+ txtLog.getText());
if(Current>8)
lblDanger.setVisible(true);
}
setGasBoilerStatus();
if(!isGasOn)
{
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
//Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
}
lblGasStatus.setText("Off");
if(Current != 0)
lblTemperatureSensor.setText("decreasing");
else
lblTemperatureSensor.setText("----");
}
}
}
}
private synchronized void decreaseTemeture() throws InterruptedException
{
synchronized (monitor) {
if(getBoilerStatus())
{
tempDown.wait();
//return;
}
else
{
Thread.sleep(4000);
if(Current == 0 )
return;
Current --;
lblCurrentTemp.setText(String.valueOf(Current));
lblDanger.setVisible(false);
txtLog.setText("Temperature decreased to " + Current + "\n"+ txtLog.getText());
if(Current<1)
lblPumpStatus.setText("Off");
else
lblPumpStatus.setText("On");
setGasBoilerStatus();
}
}
}
private void systemInitial()
{
lblDanger.setVisible(false);
isPilotOn.setSelected(true);
lblGasStatus.setText("Off");
lblPumpStatus.setText("Off");
isDone = true;
isGasOn = false;
Max = Current = 0;
}
// indicates if the boiler is on (true) or off (false)
// set as volatile to stop caching
private volatile boolean isBoilerOn = false;
protected int Max, Current;
protected boolean isDone, isGasOn, isPumpOn;
private temperatureUp tempUp;
private temperatureDown tempDown;
// Used to synchronize thread access to internal state (Current and
// isBoilerOn member variables. The monitor is private in order
// for this class to encapsulate its synchronization policy.
private final Object monitor = new Object();
// update the bolier's status to on (true) or off (false)
public void setBoilerSatus(boolean status) {
synchronized (monitor) {
// block threads until boiler is switched on
this.isBoilerOn = status;
// (see below), this is the place to notify them...
notifyAll();
}
}
// returns true if the boiler is on, false otherwise
public synchronized boolean getBoilerStatus() {
synchronized (monitor) {
return this.isBoilerOn;
}
}
private void setGasBoilerStatus() {
synchronized (monitor) {
if(Max>Current)
setBoilerSatus(true);
else
setBoilerSatus(false);
}
}
class temperatureUp extends Thread
{
#Override
public void run()
{
while(true)
{
try
{
increaseTemeture();
}
catch(Exception ex)
{
StringWriter w = new StringWriter();
ex.printStackTrace(new PrintWriter(w));
//txtLog.setText(w + "\n" + txtLog.getText());
}
}
}
};
class temperatureDown extends Thread
{
#Override
public void run()
{
while(true)
{
try
{
decreaseTemeture();
}
catch(Exception ex)
{
StringWriter w = new StringWriter();
ex.printStackTrace(new PrintWriter(w));
//txtLog.setText(w + "\n" + txtLog.getText());
}
}
}
};
`
Try creating a class Thermostat that encapsulate's your thermostat's state and behaviors. The trick is to use proper synchronization in order to maintain your program's invariants. Below you may find a sample implementation of a Thermostat class based on your requirements description, for illustration purposes. Notice how synchronization is used in order to preserve your invariants. Any method (such as up(int) and down(int) which both affect the current temperature) may be invoked concurrently by different threads, without race events or related hazards due to synchronization.
Again, this is for illustration purposes only:
public final class Thermostat {
// constant for maximum allowable temperature
public static final int MAX_TEMP = 100;
// the thermostat's current temperature
private int temp = 0;
// indicates if the boiler is on (true) or off (false)
private boolean boilerStatus = false;
public Thermostat() {
}
// Used to synchronize thread access to internal state (temp and
// boilerStatus member variables. The monitor is private in order
// for this class to encapsulate its synchronization policy.
private final Object monitor = new Object();
// update the bolier's status to on (true) or off (false)
public void setBoilerOn(boolean status) {
synchronized (monitor) {
this.boilerStatus = status;
// if you block threads until boiler is switched on
// (see below), this is the place to notify them...
}
}
// returns true if the boiler is on, false otherwise
public boolean isBoilerOn() {
synchronized (monitor) {
return this.boilerStatus;
}
}
// increase the thermostat's temperature by the specified units
// provided that the boiler has been set on
public void up(int units) {
synchronized (monitor) {
// don't increase the temperature if the boiler
// is not turned on...
if (!isBoilerOn()) {
// you could alternatively wait here if your
// thread needs to block...
return;
}
// increase the temperature
if ((temp + units) <= MAX_TEMP) {
temp += units;
} else {
// TODO : handle incorect user input here...
}
}
}
// decrease the thermostat's temperature by the specified units
// (negative values allowed)
public void down(int units) {
synchronized (monitor) {
temp -= units;
}
}
}
Try using the Full class name (dot) this
eg:
notifyGasBoiler(MyTempClass.this);

Scoped interrupts, do they exist?

I'm in requirement of some system to give me scoped interrupts, such that interrupting a thread is disabled when Thread.sleep(..) isn't executing. I'd normally use guarded blocks which would work fine, but there's a few reasons why I can't in this case, mainly because contention prevents the entire thing from working properly. The simulation just freezes up in a few seconds. Scoped interrupts would replace any blocking mechanism and prevent the interrupt from 'leaking' outside the method which the interrupt is being tested on. In this case, it'd be Thread.sleep(...). However, I'm wonder if this is asking for something which is fundamentally impossible in Java. Maybe the guarded blocking mechanism is the best that can be done.
I've created my own implementation of a Selector for use on a network simulator (the selector interacts with simulator callbacks and such for optimisation), and basically I'm using a CountDownLatch at the moment. This is good in some situations, while in others it creates even worse blocking, while not freezing up the entire simulation per-se (however, it is so slow as to be unworkable). Depends on the networking framework used as to what parts of the code get hit more than others. I also think that in the 'good' simulations the problem may arise, rarely, causing waits of 13ms and so while the internal CountDownLatch is acquired or whatever magic goes on within.
If you can solve the issue without any of the above suggestions, that'd be amazing :) Anyway, my code is below:
/**
*
*/
package kokunet;
import java.io.IOException;
import java.nio.channels.ClosedSelectorException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import kokuks.IConnectionSocket;
import kokuks.KKSAddress;
import kokuks.KKSSocket;
import kokuks.KKSSocketListener;
public class KSelector extends SelectorImpl {
// True if this Selector has been closed
private volatile boolean closed = false;
// Lock for close and cleanup
final class CloseLock {}
private final Object closeLock = new CloseLock();
private volatile boolean selecting = false;
private volatile boolean wakeup = false;
class SocketListener implements KKSSocketListener {
protected volatile CountDownLatch latch = null;
/**
*
*/
public SocketListener() {
newLatch();
}
protected synchronized CountDownLatch newLatch() {
return this.latch = new CountDownLatch(1);
}
protected synchronized void refreshReady(KKSSocket socket) {
if (!selecting) return;
synchronized (socketToChannel) {
SelChImpl ch = socketToChannel.get(socket);
if (ch == null) {
System.out.println("ks sendCB: channel not found for socket: " + socket);
return;
}
synchronized (channelToKey) {
SelectionKeyImpl sk = channelToKey.get(ch);
if (sk != null) {
if (handleSelect(sk)) {
latch.countDown();
}
}
}
}
}
#Override
public void connectionSucceeded(KKSSocket socket) {
refreshReady(socket);
}
#Override
public void connectionFailed(KKSSocket socket) {
refreshReady(socket);
}
#Override
public void dataSent(KKSSocket socket, long bytesSent) {
refreshReady(socket);
}
#Override
public void sendCB(KKSSocket socket, long bytesAvailable) {
refreshReady(socket);
}
#Override
public void onRecv(KKSSocket socket) {
refreshReady(socket);
}
#Override
public void newConnectionCreated(KKSSocket socket, KKSSocket newSocket, KKSAddress remoteaddress) {
refreshReady(socket);
}
#Override
public void normalClose(KKSSocket socket) {
wakeup();
}
#Override
public void errorClose(KKSSocket socket) {
wakeup();
}
}
protected final Map<KKSSocket, SelChImpl> socketToChannel = new HashMap<KKSSocket, SelChImpl>();
protected final Map<SelChImpl, SelectionKeyImpl> channelToKey = new HashMap<SelChImpl, SelectionKeyImpl>();
protected final SocketListener currListener = new SocketListener();
SelChImpl getChannelForSocket(KKSSocket s) {
synchronized (socketToChannel) {
return socketToChannel.get(s);
}
}
SelectionKeyImpl getSelKeyForChannel(KKSSocket s) {
synchronized (channelToKey) {
return channelToKey.get(s);
}
}
protected boolean markRead(SelectionKeyImpl impl) {
synchronized (impl) {
if (!impl.isValid()) return false;
impl.nioReadyOps(impl.readyOps() | SelectionKeyImpl.OP_READ);
return selectedKeys.add(impl);
}
}
protected boolean markWrite(SelectionKeyImpl impl) {
synchronized (impl) {
if (!impl.isValid()) return false;
impl.nioReadyOps(impl.readyOps() | SelectionKeyImpl.OP_WRITE);
return selectedKeys.add(impl);
}
}
protected boolean markAccept(SelectionKeyImpl impl) {
synchronized (impl) {
if (!impl.isValid()) return false;
impl.nioReadyOps(impl.readyOps() | SelectionKeyImpl.OP_ACCEPT);
return selectedKeys.add(impl);
}
}
protected boolean markConnect(SelectionKeyImpl impl) {
synchronized (impl) {
if (!impl.isValid()) return false;
impl.nioReadyOps(impl.readyOps() | SelectionKeyImpl.OP_CONNECT);
return selectedKeys.add(impl);
}
}
/**
* #param provider
*/
protected KSelector(SelectorProvider provider) {
super(provider);
}
/* (non-Javadoc)
* #see kokunet.SelectorImpl#implClose()
*/
#Override
protected void implClose() throws IOException {
provider().getApp().printMessage("implClose: closed: " + closed);
synchronized (closeLock) {
if (closed) return;
closed = true;
for (SelectionKey sk : keys) {
provider().getApp().printMessage("dereg1");
deregister((AbstractSelectionKey)sk);
provider().getApp().printMessage("dereg2");
SelectableChannel selch = sk.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
implCloseInterrupt();
}
}
protected void implCloseInterrupt() {
wakeup();
}
private boolean handleSelect(SelectionKey k) {
synchronized (k) {
boolean notify = false;
if (!k.isValid()) {
k.cancel();
((SelectionKeyImpl)k).channel.socket().removeListener(currListener);
return false;
}
SelectionKeyImpl ski = (SelectionKeyImpl)k;
if ((ski.interestOps() & SelectionKeyImpl.OP_READ) != 0) {
if (ski.channel.socket().getRxAvailable() > 0) {
notify |= markRead(ski);
}
}
if ((ski.interestOps() & SelectionKeyImpl.OP_WRITE) != 0) {
if (ski.channel.socket().getTxAvailable() > 0) {
notify |= markWrite(ski);
}
}
if ((ski.interestOps() & SelectionKeyImpl.OP_CONNECT) != 0) {
if (!ski.channel.socket().isConnectionless()) {
IConnectionSocket cs = (IConnectionSocket)ski.channel.socket();
if (!ski.channel.socket().isAccepting() && !cs.isConnecting() && !cs.isConnected()) {
notify |= markConnect(ski);
}
}
}
if ((ski.interestOps() & SelectionKeyImpl.OP_ACCEPT) != 0) {
//provider().getApp().printMessage("accept check: ski: " + ski + ", connectionless: " + ski.channel.socket().isConnectionless() + ", listening: " + ski.channel.socket().isListening() + ", hasPendingConn: " + (ski.channel.socket().isConnectionless() ? "nope!" : ((IConnectionSocket)ski.channel.socket()).hasPendingConnections()));
if (!ski.channel.socket().isConnectionless() && ski.channel.socket().isListening()) {
IConnectionSocket cs = (IConnectionSocket)ski.channel.socket();
if (cs.hasPendingConnections()) {
notify |= markAccept(ski);
}
}
}
return notify;
}
}
private boolean handleSelect() {
boolean notify = false;
// get initial status
for (SelectionKey k : keys) {
notify |= handleSelect(k);
}
return notify;
}
/* (non-Javadoc)
* #see kokunet.SelectorImpl#doSelect(long)
*/
#Override
protected int doSelect(long timeout) throws IOException {
processDeregisterQueue();
long timestartedms = System.currentTimeMillis();
synchronized (selectedKeys) {
wakeup = false;
selecting = true;
try {
handleSelect();
if (!selectedKeys.isEmpty() || timeout == 0) {
return selectedKeys.size();
}
//TODO: useless op if we have keys available
for (SelectionKey key : keys) {
((SelectionKeyImpl)key).channel.socket().addListener(currListener);
}
try {
while (!wakeup && isOpen() && selectedKeys.isEmpty()) {
CountDownLatch latch = null;
synchronized (currListener) {
if (wakeup || !isOpen() || !selectedKeys.isEmpty()) {
break;
}
latch = currListener.newLatch();
}
try {
if (timeout > 0) {
long currtimems = System.currentTimeMillis();
long remainingMS = (timestartedms + timeout) - currtimems;
if (remainingMS > 0) {
latch.await(remainingMS, TimeUnit.MILLISECONDS);
} else {
break;
}
} else {
latch.await();
}
} catch (InterruptedException e) {
wakeup();
}
}
return selectedKeys.size();
} finally {
for (SelectionKey key : keys) {
((SelectionKeyImpl)key).channel.socket().removeListener(currListener);
}
processDeregisterQueue();
}
} finally {
selecting = false;
wakeup = false;
}
}
}
/* (non-Javadoc)
* #see kokunet.SelectorImpl#implRegister(kokunet.SelectionKeyImpl)
*/
#Override
protected void implRegister(SelectionKeyImpl ski) {
synchronized (closeLock) {
if (closed) throw new ClosedSelectorException();
synchronized (channelToKey) {
synchronized (socketToChannel) {
keys.add(ski);
socketToChannel.put(ski.channel.socket(), ski.channel);
channelToKey.put(ski.channel, ski);
}
}
}
}
/* (non-Javadoc)
* #see kokunet.SelectorImpl#implDereg(kokunet.SelectionKeyImpl)
*/
#Override
protected void implDereg(SelectionKeyImpl ski) throws IOException {
synchronized (channelToKey) {
synchronized (socketToChannel) {
keys.remove(ski);
socketToChannel.remove(ski.channel.socket());
channelToKey.remove(ski.channel);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
}
}
}
/* (non-Javadoc)
* #see kokunet.SelectorImpl#wakeup()
*/
#Override
public Selector wakeup() {
synchronized (selectedKeys) {
wakeup = true;
selectedKeys.notifyAll();
}
return this;
}
}
Sorry for not posting an SCEE in this case, but in this case it's a bit difficult. Any suggestions would be helpful.
Cheers,
Chris
Scoped interrupts do not exist.
However, when a sleep or wait or whatever terminates with an InterruptedException the "interrupted" flag will have been cleared before the exception is thrown. So if you catch the exception at some block boundary you've sort of got scoping. Similarly, Thread.interrupted() tests and clears the "interrupted" flag.
On reading your code more carefully, I realize that you are (in fact) not using interrupts at all. Rather you are using notify and notify only wakes up a thread that is executing a wait.

how to restart a thread

I tried to write a file monitor which will check the file if a new line is appended,the monitor in fact is a thread which will read the line by a randomaccessfile all the time.
This is the monitor core codes:
public class Monitor {
public static Logger log = Logger.getLogger(Monitor.class);
public static final Monitor instance = new Monitor();
private static final ArrayList<Listener> registers = new ArrayList<Listener>();
private Runnable task = new MonitorTask();
private Thread monitorThread = new Thread(task);
private boolean beStart = true;
private static RandomAccessFile raf = null;
private File monitoredFile = null;
private long lastPos;
public void register(File f, Listener listener) {
this.monitoredFile = f;
registers.add(listener);
monitorThread.start();
}
public void replaceFile(File newFileToBeMonitored) {
this.monitoredFile = newFileToBeMonitored;
// here,how to restart the monitorThread?
}
private void setRandomFile() {
if (!monitoredFile.exists()) {
log.warn("File [" + monitoredFile.getAbsolutePath()
+ "] not exist,will try again after 30 seconds");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setRandomFile();
return;
}
try {
if (raf != null) {
raf.close();
lastPos = 0;
}
raf = new RandomAccessFile(monitoredFile, "r");
log.info("monitor file " + monitoredFile.getAbsolutePath());
} catch (FileNotFoundException e) {
// The file must exist now
} catch (IOException e) {}
}
private void startRead() {
beStart = true;
String line;
while (beStart) {
try {
raf.seek(lastPos);
while ((line = raf.readLine()) != null) {
fireEvent(new FileEvent(monitoredFile.getAbsolutePath(),
line));
}
lastPos = raf.getFilePointer();
} catch (IOException e1) {}
}
}
private void stopRead() {
this.beStart = false;
}
private void fireEvent(FileEvent event) {
for (Listener lis : registers) {
lis.lineAppended(event);
}
}
private class MonitorTask implements Runnable {
#Override
public void run() {
stopRead();
//why putting the resetReandomAccessFile in this thread method is that it will sleep if the file not exist.
setRandomFile();
startRead();
}
}
}
This is some help classes:
public interface Listener {
void lineAppended(FileEvent event);
}
public class FileEvent {
private String line;
private String source;
public FileEvent(String filepath, String addedLine) {
this.line = addedLine;
this.source = filepath;
}
//getter and setter
}
And this is a example to call the monitor:
public class Client implements Listener {
private static File f = new File("D:/ab.txt");
public static void main(String[] args) {
Monitor.instance.register(f, new Client());
System.out.println(" I am done in the main method");
try {
Thread.sleep(5000);
Monitor.instance.replaceFile(new File("D:/new.txt"));
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
#Override
public void lineAppended(FileEvent event) {
String line = event.getLine();
if (line.length() <= 0)
return;
System.err.println("found in listener:" + line + ":" + line.length());
}
}
Now,my probelm is the code work well if I just call:
Monitor.instance.register(file,listener);
This will monitor the file for line appending,and will notify the listener.
However it does not work when I call the :
Monitor.instance.replaceFile(anotherfile);
This means I want to monitor another file rather than before.
So in my Monitor I have to restart the thread,how to make it?
I have tried the:
monitorThread.interruppt();
It does not wrok.
Anyone can fix it for me or tell me how to do ?
Thanks.
Before I ask,I have googling the "restart java thread",so I know one can not restart a dead thread,but my thread does not return,so I think it can be restarted.
You don't restart a Thread, instead you create a new one each time you want to start a thread.
A better alternative may be to use Executors.newCachedThreadPool() which gives you a pool of thread which will be started/recycle for you.
BTW: You are using recursion rather than a loop to poll if the file exists. Using recursion can mean if you wait too long it will throw a StackOverflowError. IMHO you shouldn't wait at all, the polling thread should repeatedly attempt to open the file until it is told to stop (or the file appears)
Your current implementation also means if the file is replaced, you will have to reopen the file in the background thread anyway.
Instead of explaining, I just coded up a skeleton example. I did not test it terribly well, but it may be of some use.
In order to monitor a(nother) file, just create a new Monitor, passing it a ScheduledExecutorService. Starting and stopping monitoring is straightforward. You can (should) reuse the same executor for multiple monitors.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public interface Event
{
}
public interface Listener
{
void handle(Event event);
}
public class Monitor
{
private static final int CHECK_EVERY_SECONDS = 10;
private static final int RECHECK_AFTER_IF_NOT_EXISTS_SECONDS = 30;
private File file;
private ScheduledExecutorService executor;
private boolean active;
private List<Listener> listeners;
public Monitor(File file, ScheduledExecutorService executor)
{
super();
this.file = file;
this.executor = executor;
listeners = new ArrayList<Listener>();
}
public synchronized void start()
{
if (active)
{
return;
}
active = true;
executor.execute(new Runnable()
{
public void run()
{
synchronized (Monitor.this)
{
if (!active)
{
System.out.println("not active");
return;
}
}
if (!file.exists())
{
System.out.println("does not exist, rescheduled");
executor.schedule(this, RECHECK_AFTER_IF_NOT_EXISTS_SECONDS, TimeUnit.SECONDS);
return;
}
Event event = doStuff(file);
System.out.println("generated " + event);
updateListeners(event);
System.out.println("updated listeners and rescheduled");
executor.schedule(this, CHECK_EVERY_SECONDS, TimeUnit.SECONDS);
}
});
}
private Event doStuff(final File file)
{
return new Event()
{
public String toString()
{
return "event for " + file;
}
};
}
public synchronized void stop()
{
active = false;
}
public void addListener(Listener listener)
{
synchronized (listeners)
{
listeners.add(listener);
}
}
public void removeListener(Listener listener)
{
synchronized (listeners)
{
listeners.remove(listener);
}
}
private void updateListeners(Event event)
{
synchronized (listeners)
{
for (Listener listener : listeners)
{
listener.handle(event);
}
}
}
public static void main(String[] args) throws IOException
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
File file = new File("test.png");
Monitor monitor = new Monitor(file, executor);
monitor.addListener(new Listener()
{
public void handle(Event event)
{
System.out.println("handling " + event);
}
});
monitor.start();
System.out.println("started...");
System.in.read();
monitor.stop();
System.out.println("done");
executor.shutdown();
}
}
See this post How to start/stop/restart a thread in Java?
I assume you answered your question
one can not restart a dead thread
This link may be helpful to you How to restart thread in java?
A thread in Java cannot be re-started. Every time you need to restart the thread you must make a new one.
That said, you might want to look at:
private void setRandomFile() {
if (!monitoredFile.exists()) {
log.warn("File [" + monitoredFile.getAbsolutePath()
+ "] not exist,will try again after 30 seconds");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setRandomFile();
return;
}
// ....
}
Here you sleep for 30 seconds if the file does not exist, then recursively call the same function. Now, I don't know what business requirements you have, but if this recursion ran long enough you will run out of stack space. Perhaps you will be better served with a while loop or even better, a little synchronisation like a Semaphore.

Categories

Resources