I am working on java version upgrade project and I am on the work where I need to replace deprecated methods.
this.stop();
Code USed this method are in ::
ThreadedTestGroup.java::
package utmj.threaded;
import junit.framework.*;
public class ThreadedTestGroup extends ThreadGroup {
private Test test;
private TestResult testResult;
public ThreadedTestGroup(Test test) {
super("ThreadedTestGroup");
this.test = test;
}
public void interruptThenStop() {
this.interrupt();
if (this.activeCount() > 0) {
this.stop(); // For those threads which won't interrupt
}
}
public void setTestResult(TestResult result) {
testResult = result;
}
public void uncaughtException(Thread t, Throwable e) {
if (e instanceof ThreadDeath) {
return;
}
if (e instanceof AssertionFailedError) {
testResult.addFailure(test, (AssertionFailedError) e);
} else {
testResult.addError(test, e);
}
this.interruptThenStop();
}
}
CobcyrrentTestCase.java
package utmj.threaded;
import java.util.*;
import junit.framework.*;
/
public class ConcurrentTestCase extends TestCase {
private TestResult currentResult;
private ThreadedTestGroup threadGroup;
private Hashtable threads = new Hashtable();
private boolean deadlockDetected = false;
private Vector checkpoints = new Vector();
class ConcurrentTestThread extends Thread {
private volatile boolean hasStarted = false;
private volatile boolean hasFinished = false;
ConcurrentTestThread(
ThreadGroup group,
Runnable runnable,
String name) {
super(group, runnable, name);
}
public void run() {
hasStarted = true;
super.run();
finishThread(this);
}
}
public ConcurrentTestCase(String name) {
super(name);
}
public ConcurrentTestCase() {
super();
}
protected void addThread(String name, final Runnable runnable) {
if (threads.get(name) != null) {
fail("Thread with name '" + name + "' already exists");
}
ConcurrentTestThread newThread =
new ConcurrentTestThread(threadGroup, runnable, name);
threads.put(name, newThread);
}
public synchronized void checkpoint(String checkpointName) {
checkpoints.addElement(checkpointName);
this.notifyAll();
}
public boolean checkpointReached(String checkpointName) {
return checkpoints.contains(checkpointName);
}
public boolean deadlockDetected() {
return deadlockDetected;
}
private synchronized void finishThread(ConcurrentTestThread thread) {
thread.hasFinished = true;
this.notifyAll();
}
private ConcurrentTestThread getThread(String threadName) {
return (ConcurrentTestThread) threads.get(threadName);
}
/**
* Returns true if the thread finished normally, i.e. was not inerrupted or stopped
*/
public boolean hasThreadFinished(String threadName) {
ConcurrentTestThread thread = this.getThread(threadName);
if (thread == null) {
fail("Unknown Thread: " + threadName);
}
return thread.hasFinished;
}
public boolean hasThreadStarted(String threadName) {
ConcurrentTestThread thread = this.getThread(threadName);
if (thread == null) {
fail("Unknown Thread: " + threadName);
}
return thread.hasStarted;
}
private void interruptAllAliveThreads() {
threadGroup.interruptThenStop();
}
/**
* Wait till all threads have finished. Wait maximally millisecondsToWait.
* Should only be called after startThreads().
*/
protected void joinAllThreads(long millisecondsToWait) {
Enumeration enum1 = threads.elements();
long remainingMilliseconds = millisecondsToWait;
while (enum1.hasMoreElements()) {
long before = System.currentTimeMillis();
ConcurrentTestThread each =
(ConcurrentTestThread) enum1.nextElement();
try {
each.join(remainingMilliseconds);
} catch (InterruptedException ignored) {
}
long spent = System.currentTimeMillis() - before;
if (millisecondsToWait != 0) {
remainingMilliseconds = remainingMilliseconds - spent;
if (remainingMilliseconds <= 0) {
deadlockDetected = true;
break;
}
}
}
}
public void joinThread(String threadName) throws InterruptedException {
this.joinThread(threadName, 0);
}
public void joinThread(String threadName, long millisecondsToTimeout)
throws InterruptedException {
ConcurrentTestThread thread = this.getThread(threadName);
if (thread == null) {
fail("Unknown Thread: " + threadName);
}
thread.join(millisecondsToTimeout);
}
/**
* Stores the current result to be accessible during the test
*/
public void run(TestResult result) {
currentResult = result;
super.run(result);
}
protected void setUp() throws Exception {
threadGroup = new ThreadedTestGroup(this);
}
/**
* Sleep and ignore interruption
*/
public void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException ignored) {
}
}
/**
* Run all threads and wait for them to finish without timeout
*/
protected void startAndJoinAllThreads() {
this.startAndJoinThreads(0);
}
protected void startThreads() {
threadGroup.setTestResult(currentResult);
Enumeration enum1 = threads.elements();
while (enum1.hasMoreElements()) {
ConcurrentTestThread each =
(ConcurrentTestThread) enum1.nextElement();
each.start();
each.hasStarted = true;
}
Thread.yield();
}
protected void tearDown() throws Exception {
this.interruptAllAliveThreads();
threads = new Hashtable();
checkpoints = new Vector();
deadlockDetected = false;
threadGroup = null;
currentResult = null;
}
public synchronized void waitForCheckpoint(String checkpointName) {
while (!this.checkpointReached(checkpointName)) {
try {
this.wait();
} catch (InterruptedException ignored) {
}
}
}
public synchronized void waitUntilFinished(String threadName) {
while (!this.hasThreadFinished(threadName)) {
try {
this.wait();
} catch (InterruptedException ignored) {
}
}
}
}
I tried to search lot about this but did not got suitable solution so is there anyone who can help me out to replace this.stop() method which is deprecated.
IDE message: The method stop() from the type ThreadGroup is deprecated
There is no single method that replaces stop() from Thread Group but rather a design approach
From the oracle documentation it says
Many uses of stop should be replaced by code that simply modifies
some variable to indicate that the target thread should stop running.
The target thread should check this variable regularly, and return
from its run method in an orderly fashion if the variable indicates
that it is to stop running
Looking at the samples on What should I use instead of Thread.stop?
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
Throughout your thread, you need to check on a thread safe variable (in the example above its blinker) ... when stop is called, it sets the thread to null breaking out of the while loop and returning from run... thereby "stopping" the thread
Well I red a bit of the documentation about why stop() is deprecated and here is the most relevant part :
This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior. Many uses of stop should be replaced by code that simply m>odifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. If the target thread waits for long periods (on a condition variable, for example), the interrupt method should be used to interrupt the wait.
With those details, I think there is no more a simple way to stop all the threads as stop() did. You might need to modifie the threads so that you have a way to stop them (if it is possible for you).
Related
This question already has answers here:
How I can replace deprecated method this.stop() in ThreadGroup
(2 answers)
Closed 3 years ago.
I am working on java version upgrade project and I am on the work where I need to replace deprecated methods.
this.stop();
Code USed this method are in ::
ThreadedTestGroup.java::
package utmj.threaded;
import junit.framework.*;
public class ThreadedTestGroup extends ThreadGroup {
private Test test;
private TestResult testResult;
public ThreadedTestGroup(Test test) {
super("ThreadedTestGroup");
this.test = test;
}
public void interruptThenStop() {
this.interrupt();
if (this.activeCount() > 0) {
this.stop(); // For those threads which won't interrupt
}
}
public void setTestResult(TestResult result) {
testResult = result;
}
public void uncaughtException(Thread t, Throwable e) {
if (e instanceof ThreadDeath) {
return;
}
if (e instanceof AssertionFailedError) {
testResult.addFailure(test, (AssertionFailedError) e);
} else {
testResult.addError(test, e);
}
this.interruptThenStop();
}
}
ConcurrentTestCase.java
package utmj.threaded;
import java.util.*;
import junit.framework.*;
/
public class ConcurrentTestCase extends TestCase {
private TestResult currentResult;
private ThreadedTestGroup threadGroup;
private Hashtable threads = new Hashtable();
private boolean deadlockDetected = false;
private Vector checkpoints = new Vector();
class ConcurrentTestThread extends Thread {
private volatile boolean hasStarted = false;
private volatile boolean hasFinished = false;
ConcurrentTestThread(
ThreadGroup group,
Runnable runnable,
String name) {
super(group, runnable, name);
}
public void run() {
hasStarted = true;
super.run();
finishThread(this);
}
}
public ConcurrentTestCase(String name) {
super(name);
}
public ConcurrentTestCase() {
super();
}
protected void addThread(String name, final Runnable runnable) {
if (threads.get(name) != null) {
fail("Thread with name '" + name + "' already exists");
}
ConcurrentTestThread newThread =
new ConcurrentTestThread(threadGroup, runnable, name);
threads.put(name, newThread);
}
public synchronized void checkpoint(String checkpointName) {
checkpoints.addElement(checkpointName);
this.notifyAll();
}
public boolean checkpointReached(String checkpointName) {
return checkpoints.contains(checkpointName);
}
public boolean deadlockDetected() {
return deadlockDetected;
}
private synchronized void finishThread(ConcurrentTestThread thread) {
thread.hasFinished = true;
this.notifyAll();
}
private ConcurrentTestThread getThread(String threadName) {
return (ConcurrentTestThread) threads.get(threadName);
}
/**
* Returns true if the thread finished normally, i.e. was not inerrupted or stopped
*/
public boolean hasThreadFinished(String threadName) {
ConcurrentTestThread thread = this.getThread(threadName);
if (thread == null) {
fail("Unknown Thread: " + threadName);
}
return thread.hasFinished;
}
public boolean hasThreadStarted(String threadName) {
ConcurrentTestThread thread = this.getThread(threadName);
if (thread == null) {
fail("Unknown Thread: " + threadName);
}
return thread.hasStarted;
}
private void interruptAllAliveThreads() {
threadGroup.interruptThenStop();
}
/**
* Wait till all threads have finished. Wait maximally millisecondsToWait.
* Should only be called after startThreads().
*/
protected void joinAllThreads(long millisecondsToWait) {
Enumeration enum1 = threads.elements();
long remainingMilliseconds = millisecondsToWait;
while (enum1.hasMoreElements()) {
long before = System.currentTimeMillis();
ConcurrentTestThread each =
(ConcurrentTestThread) enum1.nextElement();
try {
each.join(remainingMilliseconds);
} catch (InterruptedException ignored) {
}
long spent = System.currentTimeMillis() - before;
if (millisecondsToWait != 0) {
remainingMilliseconds = remainingMilliseconds - spent;
if (remainingMilliseconds <= 0) {
deadlockDetected = true;
break;
}
}
}
}
public void joinThread(String threadName) throws InterruptedException {
this.joinThread(threadName, 0);
}
public void joinThread(String threadName, long millisecondsToTimeout)
throws InterruptedException {
ConcurrentTestThread thread = this.getThread(threadName);
if (thread == null) {
fail("Unknown Thread: " + threadName);
}
thread.join(millisecondsToTimeout);
}
/**
* Stores the current result to be accessible during the test
*/
public void run(TestResult result) {
currentResult = result;
super.run(result);
}
protected void setUp() throws Exception {
threadGroup = new ThreadedTestGroup(this);
}
/**
* Sleep and ignore interruption
*/
public void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException ignored) {
}
}
/**
* Run all threads and wait for them to finish without timeout
*/
protected void startAndJoinAllThreads() {
this.startAndJoinThreads(0);
}
protected void startThreads() {
threadGroup.setTestResult(currentResult);
Enumeration enum1 = threads.elements();
while (enum1.hasMoreElements()) {
ConcurrentTestThread each =
(ConcurrentTestThread) enum1.nextElement();
each.start();
each.hasStarted = true;
}
Thread.yield();
}
protected void tearDown() throws Exception {
this.interruptAllAliveThreads();
threads = new Hashtable();
checkpoints = new Vector();
deadlockDetected = false;
threadGroup = null;
currentResult = null;
}
public synchronized void waitForCheckpoint(String checkpointName) {
while (!this.checkpointReached(checkpointName)) {
try {
this.wait();
} catch (InterruptedException ignored) {
}
}
}
public synchronized void waitUntilFinished(String threadName) {
while (!this.hasThreadFinished(threadName)) {
try {
this.wait();
} catch (InterruptedException ignored) {
}
}
}
}
I tried to search lot about this but did not got suitable solution so is there anyone who can help me out to replace this.stop() method which is deprecated.
IDE message: The method stop() from the type ThreadGroup is deprecated
The javadoc is pretty clear about this:
Deprecated. This method is inherently unsafe. See Thread.stop() for details.
And in the javadoc for Thread, it goes on and on:
Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). ...
The problem here: this is neither a new nor an "easy to solve" problem.
My recommendation how to approach this:
if you really care about this code base, then throw it away. Don't try to refactor something that was build on inherently bad ideas. Instead: evaluate your current requirements, and design something new that addresses them.
if you were told "we should fix deprecated stuff", then simply keep things as they are. But do spend some hours testing that existing code in your new setup. When things still work, then tell the person who made this request: "that reflection work would be really really expensive, but it seems things are still working. so let's just keep using it".
In other words: it might be possible to just do "minimal" changes to get rid of stop(), but changes are that you have to invest a lot of time. And you see, multi threaded code is really hard to get right, and even harder to properly test. Therefore it is hard to predict the cost of a "minimal refactoring", thus, as said: consider throwing it all away or keeping it as is.
I cannot figure it out, how can I wake up RecursiveTasks, invoked by ForkJoinPool, when these tasks are on hold by wait method. Here is my simple example with the method MainRecursionClass.resume which is incorrect (does not wakes up RecursiveTasks).
public class Program {
public static void main(String[] args) {
Program p = new Program();
final MainRecursionClass mrc = p.new MainRecursionClass();
//Thread outputs integers to simulate work
new Thread() {
public void run() {
mrc.doJob();
}
}.start();
//Thread performs wait and notify on MainRecursionClass object
p.new PauseResume(mrc).start();
}
/**
*
* This class performs suspend and resume operations to the MainRecursionClass class object
*
*/
private class PauseResume extends Thread {
private MainRecursionClass rv;
public PauseResume(MainRecursionClass rv) {
this.rv = rv;
}
#Override
public void run() {
while(!isInterrupted()) {
try {
sleep(4000);
rv.suspend();
sleep(8000);
rv.resume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class MainRecursionClass {
private boolean pause = false;
private MyRecursive rv;
public void doJob() {
rv = new MyRecursive(0, 100000);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(rv);
}
public void suspend() {
pause = true;
System.out.println("Suspended");
}
/**
* This method is incorrect. It should wake up all MyRecursive instances to continue their work.
*/
public synchronized void resume() {
pause = false;
notifyAll();
System.out.println("Resumed");
}
private class MyRecursive extends RecursiveTask<Object> {
private static final long serialVersionUID = 1L;
private int start;
private int length;
private int threshold = 15;
public MyRecursive(int start, int length) {
super();
this.start = start;
this.length = length;
}
protected void computeDirectly() throws Exception {
for (int index = start; index < start + length; index++) {
//PAUSE
synchronized (this) {
try {
while(pause) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//PAUSE
//some output to simulate work...
System.out.println(index);
Thread.sleep(1000);
}
}
/**
* Recursion
*/
#Override
protected Object compute() {
if (length <= threshold) {
try {
computeDirectly();
} catch (Exception e) {
return e;
}
return null;
}
int split = length / 2;
invokeAll(new MyRecursive(start, split),
new MyRecursive(start + split, length - split));
return null;
}
}
}
}
You should not use wait/notify in the tasks running on a thread pool. If your pool is bounded, then it may cause thread starvation (a form of deadlock). If it is unbounded, too many threads can be created and main memory exhausted.
Instead, you should split your task in 2 (or more) and start subtasks according to their starting conditions. When you want a task to wait(), then refactor it so that current subtask exits, and next subtask is prepared to run.
Finally I came to this solution: I created List<MyRecursive> list = new ArrayList<>(); object in MainRecursionClass and added every MyRecursive instance, created recursively, in the list. The class MyRecursive has new method:
public synchronized void resume() {
notify();
}
When, the method MainRecursionClass.resume(), which wakes up the threads, looks like this:
public void resume() {
System.out.println("Resumed");
pause = false;
for(MyRecursive mr : list) {
if(mr != null)
mr.resume();
}
}
}
Essentially, what I want to do is start all my threads, pause them all, then resume them all, using the multithreading approach. I am just looking for a simple solution to this. I'm not sure if I have to use a timer or what. Right now when I run it, the threads are like being executed in random order (I guess the PC is just randomly picking which ones it wants to run at a certain time).
class ChoppingThread extends Thread
{
public void run()
{
for(int j=40;j!=0;j-=10)
System.out.println("Chopping vegetables...("+j+" seconds left)");
}
}
class MixingThread extends Thread
{
public void run()
{
for(int k=60;k!=0;k-=10)
System.out.println("Mixing sauces...("+k+" seconds left)");
}
}
class TenderizingThread extends Thread
{
public void run()
{
for(int j=50;j!=0;j-=10)
System.out.println("Tenderizing meat...("+j+" seconds left)");
}
}
class MultiThreadTasking
{
public static void main (String [] args)
{
ChoppingThread ct = new ChoppingThread();
MixingThread mt = new MixingThread();
TenderizingThread tt = new TenderizingThread();
System.out.println("\nWelcome to the busy kitchen.");
//putting threads into ready state
ct.start();
mt.start();
tt.start();
}
}
There are probably other ways to achieve the same result, but this is the simplest I can come up with off the top of my head (I know, sad isn't it)...
Basically, this is a special Runnable with some additional management functionality.
This basically contains a state flag that indicates the state of the task and a monitor lock
public class ThreadFun {
public static void main(String[] args) {
MyTask task = new MyTask();
Thread thread = new Thread(task);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.pauseTask();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.resumeTask();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
task.stopTask();
}
public enum TaskState {
Running,
Stopped,
Paused
}
public static class MyTask implements Runnable {
private static final Object PAUSED_LOCK = new Object();
private volatile TaskState state = TaskState.Running;
public void pauseTask() {
if (state == TaskState.Running) {
System.out.println("Paused...");
state = TaskState.Paused;
}
}
public void resumeTask() {
if (state == TaskState.Paused) {
state = TaskState.Running;
synchronized (PAUSED_LOCK) {
PAUSED_LOCK.notifyAll();
}
System.out.println("Resumed...");
}
}
public void stopTask() {
if (state == TaskState.Running || state == TaskState.Paused) {
state = TaskState.Stopped;
System.out.println("Stopped...");
}
}
public boolean isStopped() {
return state == TaskState.Stopped;
}
public boolean isPaused() {
return state == TaskState.Paused;
}
protected void doPause() {
synchronized (PAUSED_LOCK) {
while (isPaused()) {
try {
PAUSED_LOCK.wait();
} catch (InterruptedException ex) {
}
}
}
}
#Override
public void run() {
int index = 0;
while (!isStopped() && index < 1000) {
try {
Thread.sleep(25);
} catch (InterruptedException ex) {
}
doPause();
index++;
System.out.println(index);
}
stopTask(); // Make sure the task is marked as begin stopped ;)
}
}
}
The main criteria is you will need to pool isStopped and doPause at appropriate points to ensure that they are begin implemented as required...
To coordinate them use a CyclicBarrier.
To launch them all at the same time use a CountDownLatch.
Google the two classes above for many examples and explanations.
To fully understand what is happening read the Java Concurrency In Practice book.
I believe you can accomplish this by using Object.wait and Thread.interrupt.
Object.wait blocks until notify is called. So
private boolean paused;
private Object waitObject;
...
public void run() {
for ... {
if (this.paused) { this.waitObject.wait(); }
...
public void pause() { this.paused = true; }
public void resume() { this.paused = false; this.waitObject.notify(); }
Then you can call pause to pause the thread.
Thread.interrupt can help with stopping.
private boolean paused;
...
public void run() {
for ... {
// interrupted() is different from interrupt()!
if (this.iterrupted()) { break; }
...
To stop it, you would call interrupt() from another thread.
This is the basic idea, but there's a lot of details to worry about here. For example, wait can throw an InterruptedException you'll need to handle. Also, wait is not guaranteed to return only after a notify. It can return randomly. Here is a pair of tutorials:
Wait: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Interrupt: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
Very recently I've asked this question, but wasn unable to fix this. So I have a thread hunter (2 of them actually), who "goes off to catch wild boars". He stores these boars in a container Fridge. He will continue to do so until his working hours expire. However, in case the Fridge is full he has to wait. The aim is to wait until a wild boar is removed from the fridge, but if it takes more then 5 seconds of waiting test must be terminated. So everything works except one thing. After running test and interrupting these threads, the program still continues to run. So how do I completely terminate/stop these threads?
TEST CLASS (main)
class Test {
public static void main(String[] args) {
test1();
}
public static void test1() {
Fridge fridge = new Fridge(4);
Hunter hunter1 = new Hunter("hunter1", 4, fridge);
Hunter hunter2 = new Hunter("hunter2", 7, fridge);
Thread hunterThread1 = new Thread(hunter1);
Thread hunterThread2 = new Thread(hunter2);
hunterThread1.start();
hunterThread2.start();
try { Thread.sleep(1000); } catch (InterruptedException e) {}
hunterThread1.interrupt();
hunterThread2.interrupt();
System.out.println(fridge.getSize());
System.out.println(hunter1.getWorkTime());
System.out.println(hunter2.getWorkTime());
}
}
HUNTER CLASS
class Hunter extends Worker {
private int workTime;
private Fridge fridge;
public Hunter(String name, int workTime, Fridge fridge) {
super(name);
this.workTime = workTime;
this.fridge = fridge;
}
public int getWorkTime() {
return workTime;
}
public void run() {
while (workTime > 0) {
/** Each hunt takes a random amount of time (1-50 ms) **/
try { Thread.sleep(workGen()); } catch (InterruptedException e) {}
/** Add new wild boars **/
try { fridge.add(new WildBoar()); } catch (InterruptedException e) {}
workTime--;
/** If thread is interupted break the loop **/
if( Thread.currentThread().isInterrupted()){
break;
}
}
}
}
FRIDGE CLASS
import java.util.Stack;
class Fridge extends Storage {
private Stack<WildBoar> boars;
public Fridge(int cap) {
super(cap);
boars = new Stack<WildBoar>();
}
public int getCap() {
return cap;
}
public int getSize() {
return boars.size();
}
public boolean hasFreeSpace() {
if ( boars.size() < cap )
return true;
else
return false;
}
public synchronized void add(WildBoar boar) throws InterruptedException {
/** If there's no free space available wait **/
while ( !hasFreeSpace() ) {
wait();
}
/** Once there's free space available add new item **/
boars.add(boar);
}
public synchronized WildBoar remove() {
return boars.pop();
}
}
ADDITIONAL CLASSES FOR COMPILING:
abstract class Worker implements Runnable {
private String name;
public Worker(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int workGen() {
return 1 + (int)(Math.random() * (50 - 1));
}
}
class WildBoar {
public WildBoar() {}
}
abstract class Storage {
protected int cap;
public Storage(int cap) {
this.cap = cap;
}
public int getCap() {
return cap;
}
}
After you interrupt() the thread which is currently waiting, the native wait method will actually reset the interruption flag. So when you evaluate the isInterrupted() here, it is actually reset and will appear as not interrupted.
if( Thread.currentThread().isInterrupted()){
break;
}
You will have to re-interrupt the thread after an interruption occurs during the waiting
public synchronized void add(Object boar) {
/** If there's no free space available wait **/
while (!hasFreeSpace()) {
try{
wait();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
return; //or rethrow
}
}
/** Once there's free space available add new item **/
boars.add(boar);
}
Currently, the run method in your Hunter thread is discarding interruptions:
try { fridge.add(new WildBoar()); }
catch (InterruptedException e) {}
Thus, nothing happens when you later check for interruptions
if( Thread.currentThread().isInterrupted()){
break;
}
To correct this, you need to set the thread's interrupt status:
try { fridge.add(new WildBoar()); }
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Summary - ignoring the InterruptedException resets the interrupt status. If you don't or re-throw it or break, then you will need to set the interrupt status manually.
We require a piece of code to control a thread. For example, use three buttons like start, stop and pause, press one of them and perform the action against it. Like press start then start the thread, press stop actually stops thread and pause perform pause action respectively.
Starting a thread is simple with Thread.start(). Stopping a thread can be as simple as setting a flag that is checked asychronously in the run method, but may need to include a call to Thread.interrupt(). Pausing a thread is more problematic, but could also be done using a flag that cauases the run method to yield instead of process. Here is some (untested) code:
class MyThread extends Thread {
private final static int STATE_RUN = 0, STATE_PAUSE = 2, STATE_STOP = 3;
private int _state;
MyThread() {
_state = STATE_RUN;
}
public void run() {
int stateTemp;
synchronized(this) {
stateTemp = _state;
}
while (stateTemp != STATE_STOP) {
switch (stateTemp) {
case STATE_RUN:
// perform processing
break;
case STATE_PAUSE:
yield();
break;
}
synchronized(this) {
stateTemp = _state;
}
}
// cleanup
}
public synchronized void stop() {
_state = STATE_STOP;
// may need to call interrupt() if the processing calls blocking methods.
}
public synchronized void pause() {
_state = STATE_PAUSE;
// may need to call interrupt() if the processing calls blocking methods.
// perhaps set priority very low with setPriority(MIN_PRIORITY);
}
public synchronized void unpause() {
_state = STATE_RUN;
// perhaps restore priority with setPriority(somePriority);
// may need to re-establish any blocked calls interrupted by pause()
}
}
As you can see it can quite quickly get complex depending on what you are doing in the thread.
I would like to add on Richard's answer to address a few issues:
Needless cycles when paused
Needless extra cycle when state changed
yield() used where wait() needed
Single instance
Stopping the thread waits for the thread to finish
This is my altered code:
class MyThread extends Thread {
private final static int STATE_RUN = 0, STATE_PAUSE = 2, STATE_STOP = 3;
private int _state;
private static MyThread thread;
public static MyThread getInstance() {
if (thread == null || !thread.isAlive()) {
thread = new MyThread();
}
return thread;
}
private MyThread() {
_state = STATE_RUN;
}
public static void main(String[] args) {
MyThread t = MyThread.getInstance();
try {
t.start();
Thread.sleep(500);
t.pause();
Thread.sleep(500);
t.unpause();
Thread.sleep(500);
t.end();
} catch (InterruptedException e) {
// ignore; this is just an example
}
}
public void run() {
int i = 0;
while (_state != STATE_STOP) {
if (_state == STATE_PAUSE) {
System.out.println(this + " paused");
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
}
if (_state == STATE_STOP) {
break;
}
// this is where the actual processing happens
try {
// slow output down for this example
Thread.sleep(100);
} catch (InterruptedException e) {
// state change handled next cycle
}
System.out.println(this + " cycle " + i);
i++;
}
System.out.println(this + " finished");
// cleanup
}
public synchronized void end() {
_state = STATE_STOP;
try {
this.interrupt();
this.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void pause() {
_state = STATE_PAUSE;
}
public synchronized void unpause() {
_state = STATE_RUN;
synchronized (this) {
this.notify();
}
}
}