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.
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 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).
I have two threads. The first changes the value of variable Data. And second one print the value if its value has changed. I am trying to do that second thread just print each time that the variable's value changed, but I don't reach success. Someone can help me?
thread 1
class someservice{
volatile int data;
Boolean Flag = false;
public void mymethod(){
flag = true;
for (Integer i = 1; i < sheet.getRows(); i++) {
data = someMethod(); //this method when called return a new
//value
}
flag = false;
...
}
}
thread 2
Promise p = task {
try {
while (true) {
if (engineService.getFlag()) {
print(someservice.data);
}else{
break;
}
}
} catch(Throwable t) {
...
}
}
Since you mention Promises, I infer you are familiar with future/ promise in +C++11
in java there is a similar approach, with future callable...
public class HW5 {
public static void main(String[] argv) throws InterruptedException, ExecutionException {
FutureTask<Boolean> myFutureTask = new FutureTask<>(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// implement the logic here and return true if everything was
// ok, false otherwise.
Thread.sleep(5000);
System.out.println("dddd");
return System.currentTimeMillis() % 2 == 0;
}
});
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(myFutureTask);
Boolean result = myFutureTask.get();
System.out.println("Done!");
}
}
FutureTask in a class that takes a callable which can return an Object after its job is done... in Order to execute the Future task you can use a Executor service, especifically calling the method execute, since you need to wait for the thread to do the job then is necessary that you call Future.get, that will basically blocks the main thread until the future is done, to verify the result, just read the variable result..
You could use the notify() and notifyAll() methods within thread. Check out this link: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
public synchronized void guardedJoy() {
// This guard only loops once for each special event, which may not
// be the event we're waiting for.
while(!joy) {
try {
wait();
} catch (InterruptedException e) {}
}
System.out.println("Joy and efficiency have been achieved!");
}
public synchronized notifyJoy() {
joy = true;
notifyAll();
}
You have to look up more data about Concurrent programming,I can tell you now some basics,well,not so so basic,but i will do my best:
Here,you have a Monitor,it is an abstract concept,in resume,a Monitor is a
class with all it's
method using"syncronized"
as modifier, it means,
that only
one thread
can access
the method
at once.So,
in the
monitor is
the variable
that you
want to print,
and the"flag",
that tells you if
the variable
was modified.Finally,
you can
see the
most important thing,the"wait()"and"notify()"methods,
those method
stops the thread,or"play"
them again.
You ask
here in
the printValue() method, if your variable was changed, if the variable was'nt change, put the thead to sleep with the wait() method, and when the other
method changeValue() is executed, the value is modified, and the notify() method is called, waking up the thread, so, doing all this, you can guarantee three things:
Safety: meaning that the threads will do that you want
Absence of deadlock: meaning that the thread that is put to sleep, will be awake in the future.
Mutex: meaning that only one thread is executing the critical code, for example, the op. "++" is not atomic, is Subdivided inside in more the one action, create a local var, read the var, sum, and asign, so, if more than one thread are in the game, the value may not be consecutive, example:
i = 0;
i ++;
output: 1;
output: 2;
output: 3;
output: 5;
output: 4;
output: 7;
That could happen, and even so, that will happen in the next code, because there a more than one thread executing. Well, this is the way to program with several threads, more or less
public class Monitor {
private int value = 0;
public static boolean valueHasChanged = false;
public synchronized int changeValue(int newValue){
this.value = newValue;
Monitor.valueHasChanged = true;
this.notify();
return this.value + 1;
}
public synchronized void printValue(){
while(!Monitor.valueHasChanged){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(this.value);
Monitor.valueHasChanged = false;
}
public static void main(String[] args) {
Monitor ac = new Monitor();
BClass t1 = new BClass(ac);
AClass t2 = new AClass(ac);
t1.start();
t2.start();
}
public int getValue() {
return this.value;
}
}
Now the threads:
public class AClass extends Thread{
private Monitor ac;
public AClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
while(true){
this.ac.printValue();
}
}
}
And finally:
public class BClass extends Thread{
private Monitor ac;
public BClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
int v = 0;
while(true){
this.ac.changeValue(v);
v++; // this sum is not secure, if you want to print an
// ascending order, the code is diferent, I will show in
// above.
}
}
Now, if you want an ordered print:
the monitor will look like:
public class Monitor {
private int value = 0;
public boolean valueHasChanged = false;
private boolean hasPrint = true;
public synchronized void changeValue(int newValue) {
this.value = newValue;
this.valueHasChanged = true;
this.notify();
}
public synchronized void changeValuePlusOne() {
while (!hasPrint) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.value++;
this.valueHasChanged = true;
this.hasPrint = false;
this.notifyAll();
}
public synchronized void printValue() {
while (!this.valueHasChanged) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(this.value);
this.valueHasChanged = false;
this.hasPrint = true;
this.notifyAll();
}
public static void main(String[] args) {
Monitor ac = new Monitor();
BClass t1 = new BClass(ac);
AClass t2 = new AClass(ac);
t1.start();
t2.start();
}
public int getValue() {
return this.value;
}
}
And the Threads:
public class BClass extends Thread{
private Monitor ac;
public BClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
while(true){
this.ac.changeValuePlusOne();
}
}
}
The other Thread look equals:
public class AClass extends Thread{
private Monitor ac;
public AClass(Monitor ac) {
this.ac = ac;
}
#Override
public void run() {
while(true){
this.ac.printValue();
}
}
}
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