Thread not throwing an InterruptedException when interrupt() is called - java

I am working on an application that reads and processes data over a network. While testing the connecting/disconnecting logic of the program I noticed that my consumer thread was not closing when it reached it's closing condition. Below is a stripped out version of the consumer class.
import java.io.InputStream;
public class Consumer implements Runnable
{
private final InputStream input;
public Consumer(InputStream input)
{
this.input = input;
}
#Override
public void run()
{
byte readBuffer[];
readBuffer = new byte[1];
int goodData;
try
{
while(input.available() > 0)
{
goodData = input.read(readBuffer);
while (goodData > 0 )
{
System.out.println(readBuffer[0]);
if ( readBuffer[0] == 27 )
{
System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName());
//this is the last packet, so interupt thread to close
Thread.currentThread().interrupt();
//return;
//Thread.currentThread().stop(new InterruptedException("Attempting to close"));
}
goodData = input.read(readBuffer);
}
}
}
catch(Exception e)
{
System.out.println("closing "+Thread.currentThread().getName() +" because of an exception "+e.getClass());
return;
}
System.out.println("closing "+Thread.currentThread().getName());
}
}
I created a dummy main class that demonstrates the problem.
public class ExampleOfInterruptNotWorking
{
public static void main(String[] args)
{
byte[] bytesToWrite = new byte[]{0, 1, 2,3,4,5,6,65,23,65,21,54,13,54,1,76};
Consumer C;
Thread ConsumerThread;
PipedInputStream PIS = null;
PipedOutputStream POS = null;
try
{
PIS = new PipedInputStream();
POS = new PipedOutputStream(PIS);
C = new Consumer(PIS);
ConsumerThread = new Thread(C);
ConsumerThread.start();
POS.write(bytesToWrite);
POS.write(bytesToWrite);
bytesToWrite[1] = 27;
POS.write(bytesToWrite);
ConsumerThread.join();
}
catch(Exception e)
{
System.err.println("Unexpected exception in main");
e.printStackTrace(System.err);
}
finally
{
try
{
PIS.close();
POS.close();
}
catch(Exception ex)
{
//shouldn't happen in example
}
System.out.println("exiting main");
}
}
}
When you run this code as written, the consumer detects the interrupt, but does not stop execution until the pipe is empty (not what I want). Just to try, I changed to a Thread.stop() call which did what I wanted, but I don't want to leave that in production code. I realized that I could use a simple return statement, but this is not the only point the thread could exit, and I'd like to have some common exit code that cleans up resources. So, my question is, why is the consumer thread not being interrupted? and is there a good way for me to be able to have common exit code?
Thanks!

InterruptedExceptions are thrown when a thread is sleeping, waiting for a join etc. (basically any interruptable blocking call) and interrupt() is called.
If you thread is running then the thread interrupt flag will be set but no exception will be thrown, you should check the flag with myThread.isInterrupted().
You can find more information here:
http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html

Which method do you expect to throw InterruptedException? Thread.interrupt() is not throwing it, neither any of your methods. So where do you expect this checked exception should come from?
Your code is not working because interrupt() barely sets the interrupted flag on a thread. You must check that flag explicitly using Thread.isInterrupted(). InterruptedException is only thrown if the thread in question was sleeping or blocking at the time. So if you interrupt different thread and that thread was sleeping, sleep() will throw InterruptedException.
Now to address your problem in detail. Exceptions are for exceptional cases. The fact your thread finished processing is not exceptional case, it's something you definitely expect. For the same reason reading a file past the end is not throwing an exception - end of file is something you should definitely expect - all files have end. Moreover you should not use exceptions to control program flow.
In your case either use return statement (when run() returns, thread dies) or break your loop in some other way. You posted too much code to analyze.

You could simply use break to label
OUTER:
while(input.available() > 0)
{
goodData = input.read(readBuffer);
while (goodData > 0 )
{
System.out.println(readBuffer[0]);
if ( readBuffer[0] == 27 )
{
System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName());
//this is the last packet, so interupt thread to close
//Thread.currentThread().interrupt();
break OUTER;
//return;
//Thread.currentThread().stop(new InterruptedException("Attempting to close"));
}
goodData = input.read(readBuffer);
}
}

Related

Interrupt Scanner nextLine() (alternatives)

I have the following thread:
Thread t1 = new Thread() {
#Override
public void run() {
while (!progress.equals(duration)) {
try {
Thread.sleep(1000);
progress = progress.plusSeconds(1);
// synchronized (this) { while (paused) { this.wait(); } }
} catch (InterruptedException e) {
interrupt();
}
}
}
};
t1.start();
I'm trying to implement a functionality which allows the user to pause and stop this thread using the console. Basically, this:
Scanner sc = new Scanner(System.in);
int choice;
while (t1.isAlive()) {
System.out.println("Choose an option:\n1. Pause/Resume\n2. Stop");
choice = Integer.parseInt(sc.nextLine());
// if (choice == 1) { ... } else if (choice == 2) { t1.interrupt() }
// synchronized (t1) { t1.notify(); }
}
My problem is that once t1 dies, t1.isAlive() evaluates to false, but the program doesn't exit the while loop because it is stuck waiting for one last input from the user. I want to interrupt sc.nextLine(), but I read it is not possible because the thread is blocked. How could I do this?
I tried the following:
Thread t2;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (t1.isAlive()) {
t2 = new Thread() {
#Override
public void run() {
try {
while (!br.ready())
Thread.sleep(200);
choice = Integer.parseInt(br.readLine());
} catch (InterruptedException e) {
} catch (IOException e) {
}
}
};
t2.start();
}
Supposedly, this should allow me to interrupt t2, but I must be doing something wrong because it keeps printing Chose an option: 1. Pause/Resume 2. Stop, so I cannot check if it works.
The crucial issue is that the API of System.in makes no guarantees. A JVM can fulfill the complete JVM spec even if it has a System.in such that, if it is interrupted, nothing happens and it is in fact completely impossible to interrupt System.in, aside from System.exit.
However, most JVM implementations fortunately don't quite work that way: If you raise the interrupt flag on any given thread, 3 things are going to happen:
Any method that is specced to definitely look at em will be interrupted: These are all methods that are declared to throws InterruptedException. All these methods will, if the thread's interrupt flag is raised, stop waiting immediately, lower the flag, and return by way of throwing InterruptedException. Yes, this means that if you first raise the interrupt flag (someThread.interrupt() raises the flag and doesn't do anything else; it's other methods that look at it that makes the magic work), and then invoke e.g. Thread.sleep, the sleep calls returns immediately (by throwing InterruptedEx) and waits no even a single millisecond.
Methods that pause a thread but which are not specced to definitely deal with it properly are in limboland: It is up to the implementation of the java runtime if anything happens. However, usually something will happen. These methods almost always throw some sort of checked exception (for DB connections, SQLEx, for network, file, and pipe operations, IOException); any code that is currently waiting to send or receive data on one of these things will deal with a raised interrupt flag by lowering the flag, aborting the operation, and returning by way of throwing that checked exception with a message that indicates an interruption occurred.
If code is executing that doesn't respond to the interrupt flag at all, then nothing happens: The flag stays raised and the JVM is not going to do anything else; the point of the interrupt flag is that it just gets raised and then you wait until the thread runs code that looks at it. Hopefully, that will happen very soon, but there are no guarantees.
That means that most likely all you need to do is:
In T1
Have some sort of AtomicBoolean object that will be set to true by t1 once the job is completed.
t1 will also raise the interrupt flag of t2 when the job is completed.
In T2
Protect your readLine() call by putting it in a try/catch block, catching IOException. If there is a loop you may also want to consider checking the interrupt flag yourself, in case it is set in between readLine() invokes; you do this with Thread.interrupted(), which returns true and lowers the flag if the flag is up. Generally, something like while (!Thread.interrupted() && other conditions) { /* main loop here */ }.
In the IOException catch handler, check t1's 'we are done' flag (that AtomicBoolean). If it says 'we are done', then interpret the IOEx as simply being notified that the job is done (so, don't log it anywhere - you were expecting it to happen). If, however, the 'we are done' flag isn't set yet, then that IOException is indicating an actual I/O problem with the input pipe, which can happen of course. You should proceed as normal (which usually means, throw it onwards so that the app crashes with a full log, you can't sanely respond to the input pipe getting I/O issues other than to exit with debug info about what happend). So, just throw that IOException. If you can't, throw new UncheckedIOException(thatIoException); is what you are looking for.
The caveat
Just because it works on your system does not mean it will work anywhere else, unfortunately. As I said, on some VM impls System.in.read() is just not interruptable, period. Nothing you can do, other than extremely drastic steps: Stop being a command line app and show a swing GUI window instead or make it a web app of some sort.
Closing notes
ready() and available() are almost completely useless. They aren't broken, in the sense that they do exactly what their javadoc says these methods do, but if you carefully read that javadoc, you'll realize that what they provide is completely useless. The only real way to know if data is available is to actually attempt to read it, which then leads you into the trap of: Well, on some platforms, that's not interruptable. Yup. Sucks. No reliable solution, in the sense that the API guarantees it'll work on all platforms, is available. 99.5% of all code out there that calls these methods is broken. It is highly unlikely that you'd ever want to call these methods.
It looks like an innocent topic, but actually it's a bit more complicated. When you are reading from the standard input, you usually just end up in a call to the operating system. Which will not return until it has actual input to return with, and has no idea about the interruption mechanism of Java. It's described as a by-product here.
What you can do is providing your own InputStream instead of using System.in directly, and implement its read() method in a way that it goes into System.in.read() only when System.in.available() says so. Until then just repeat the check with some delay, like using Thread.sleep() which is prepared to get interrupted anyway:
public static void main(String[] args) {
Thread main = Thread.currentThread();
// try (Scanner sc = new Scanner(System.in)) {
try (Scanner sc = new Scanner(new InputStream() {
#Override
public int read() throws IOException {
while (System.in.available() == 0)
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
throw new IOException();
}
return System.in.read();
}
})) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
}
main.interrupt();
}
}).start();
String line = sc.nextLine();
System.out.println(line);
System.out.println(main.isInterrupted());
} catch (Exception ex) {
System.out.println("Time's up, probably. Actual exception: " + ex);
System.out.println(main.isInterrupted());
}
}
If you comment the try(Scanner...-})) { block and uncomment the single-line variant, you can try how it doesn't work in itself: you will always have to input something, only the result of System.out.println(main.isInterrupted()); will tell you if you did it in 5 seconds or it took more time.
Side note: in your own attempt you were interrupting the timer thread itself, you need a reference to the other thread instead, here in this example that's the Thread main variable.

How to interrupt thread to do work and then sleep after doing work?

I want to have a thread which does some I/O work when it is interrupted by a main thread and then go back to sleep/wait until the interrupt is called back again.
So, I have come up with an implementation which seems to be not working. The code snippet is below.
Note - Here the flag is a public variable which can be accessed via the thread class which is in the main class
// in the main function this is how I am calling it
if(!flag) {
thread.interrupt()
}
//this is how my thread class is implemented
class IOworkthread extends Thread {
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
} catch (InterruptedException e) {
flag = true;
try {
// doing my I/O work
} catch (Exception e1) {
// print the exception message
}
}
}
}
}
In the above snippet, the second try-catch block catches the InterruptedException. This means that both of the first and second try-catch block are catching the interrupt. But I had only called interrupt to happen during the first try-catch block.
Can you please help me with this?
EDIT
If you feel that there can be another solution for my objective, I will be happy to know about it :)
If it's important to respond fast to the flag you could try the following:
class IOworkthread extends Thread {//implements Runnable would be better here, but thats another story
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
}
catch (InterruptedException e) {
flag = true;
}
//after the catch block the interrupted state of the thread should be reset and there should be no exceptions here
try {
// doing I/O work
}
catch (Exception e1) {
// print the exception message
// here of course other exceptions could appear but if there is no Thread.sleep() used here there should be no InterruptedException in this block
}
}
}
}
This should do different because in the catch block when the InterruptedException is caught, the interrupted flag of the thread is reset (at the end of the catch block).
It does sound like a producer/consumer construct. You seem to kind of have it the wrong way around, the IO should be driving the algorithm. Since you stay very abstract in what your code actually does, I'll need to stick to that.
So let's say your "distributed algorithm" works on data of type T; that means that it can be described as a Consumer<T> (the method name in this interface is accept(T value)). Since it can run concurrently, you want to create several instances of that; this is usually done using an ExecutorService. The Executors class provides a nice set of factory methods for creating one, let's use Executors.newFixedThreadPool(parallelism).
Your "IO" thread runs to create input for the algorithm, meaning it is a Supplier<T>. We can run it in an Executors.newSingleThreadExecutor().
We connect these two using a BlockingQueue<T>; this is a FIFO collection. The IO thread puts elements in, and the algorithm instances take out the next one that becomes available.
This makes the whole setup look something like this:
void run() {
int parallelism = 4; // or whatever
ExecutorService algorithmExecutor = Executors.newFixedThreadPool(parallelism);
ExecutorService ioExecutor = Executors.newSingleThreadExecutor();
// this queue will accept up to 4 elements
// this might need to be changed depending on performance of each
BlockingQueue<T> queue = new ArrayBlockingQueue<T>(parallelism);
ioExecutor.submit(new IoExecutor(queue));
// take element from queue
T nextElement = getNextElement(queue);
while (nextElement != null) {
algorithmExecutor.submit(() -> new AlgorithmInstance().accept(nextElement));
nextElement = getNextElement(queue);
if (nextElement == null) break;
}
// wait until algorithms have finished running and cleanup
algorithmExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.YEARS);
algorithmExecutor.shutdown();
ioExecutor.shutdown(); // the io thread should have terminated by now already
}
T getNextElement(BlockingQueue<T> queue) {
int timeOut = 1; // adjust depending on your IO
T result = null;
while (true) {
try {
result = queue.poll(timeOut, TimeUnits.SECONDS);
} catch (TimeoutException e) {} // retry indefinetely, we will get a value eventually
}
return result;
}
Now this doesn't actually answer your question because you wanted to know how the IO thread can be notified when it can continue reading data.
This is achieved by the limit to the BlockingQueue<> which will not accept elements after this has been reached, meaning the IO thread can just keep reading and try to put in elements.
abstract class IoExecutor<T> {
private final BlockingQueue<T> queue;
public IoExecutor(BlockingQueue<T> q) { queue = q; }
public void run() {
while (hasMoreData()) {
T data = readData();
// this will block if the queue is full, so IO will pause
queue.put(data);
}
// put null into queue
queue.put(null);
}
protected boolean hasMoreData();
protected abstract T readData();
}
As a result during runtime you should at all time have 4 threads of the algorithm running, as well as (up to) 4 items in the queue waiting for one of the algorithm threads to finish and pick them up.

Throw new InterruptedException() instead .join()

I try to stop a thread using .interrupt() method.
Here is my code:
#Override
public void run() {
try {
for (int i = 0; i < 1000000000; i++) {
System.out.println(threadName + " generated " + i);
if (counter.isInterrupted()) {
counter.join();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
What I do not understand is that instead of this code:
if (counter.isInterrupted()) {
counter.join();
}
If I throw an InterruptedException it works as well.
if (counter.isInterrupted()) {
throw new InterruptedException();
}
What I do not understand is why I would choose one instead of another one. Also I've seen some approaches where people use an volatile boolean variable too. Is is safer than my approach?
An InterruptedException is meant to indicate that the current thread has been interrupted in the course of an operation. The issue with your second option is that you are throwing the exception on the basis of some other thread being interrupted. This will cause the wrong impression to be made by calling code.
As a rule of thumb, when you catch an InterruptedException, you should do one of three things:
Rethrow it (without a wrapper exception), so that callers know of the interruption
Re-set the interrupt(), so that the fact that this thread was interrupted is maintained
Handle the interruption (usually by cleaning up and shutting down the thread)

Consumer thread does not get notified [duplicate]

I have a thread that calls the wait method and can only be awoken when the notify method called from some other class:
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(b) {
try {
System.out.println("Waiting for b to complete...");
b.wait();
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
}
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
notify();
}
}
}
In the above code if the synchronized block in main, if the ThreadA does not execute first and instead the other synchronization block executing and completes to completion, then ThreadA executes its synchronized block and calls wait, what is going to happen and how it will be notified again?
If ThreadB gets through its synchronized block before ThreadA does, then ThreadA will block indefinitely on the call to wait. It won't somehow be notified that the other thread has already completed.
The problem is that you're trying to use wait and notify in ways that they are not designed to be used. Usually, wait and notify are used to have one thread wait until some condition is true, and then to have another thread signal that the condition may have become true. For example, they're often used as follows:
/* Producer */
synchronized (obj) {
/* Make resource available. */
obj.notify();
}
/* Consumer */
synchronized (obj) {
while (/* resource not available */)
obj.wait();
/* Consume the resource. */
}
The reason that the above code works is that it doesn't matter which thread runs first. If the producer thread creates a resource and no one is waiting on obj, then when the consumer runs it will enter the while loop, notice that the resource has been produced, and then skip the call to wait. It can then consume the resource. If, on the other hand, the consumer runs first, it will notice in the while loop that the resource is not yet available and will wait for some other object to notify it. The other thread can then run, produce the resource, and notify the consumer thread that the resource is available. Once the original thread is awoken, it will notice that the condition of the loop is no longer true and will consume the resource.
More generally, Java suggests that you always call wait in a loop because of spurious notifications in which a thread can wake up from a call to wait without ever being notified of anything. Using the above pattern can prevent this.
In your particular instance, if you want to ensure that ThreadB has finished running before ThreadA executes, you may want to use Thread.join(), which explicitly blocks the calling thread until some other thread executes. More generally, you may want to look into some of the other synchronization primitives provided by Java, as they often are much easier to use than wait and notify.
You could loop and wait until the total has been computed :
synchronized(b) {
while (total == 0) {
b.wait();
}
}
You could also use a higher-level abstraction like a CountDownLatch.
It is possible for ThreadB's run method to complete before you enter the synchronized block in ThreadA.main. In that situation, since the notify call has happened before you started waiting, ThreadA will block forever on the wait call.
A simple workaround would be to grab the lock on b in main before you start the second thread to ensure the wait happens first.
ThreadB b = new ThreadB();
synchronized(b) {
b.start();
...
b.wait();
}
You probably want to use a java.util.concurrent.Semaphore for this.
1) You need to add some flag that is used to communicate between the threads, so that B can signal to A when it is finished. A simple boolean variable is fine, as long as it is only read and written within the synchronized blocks.
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
isDone = true;
notify();
}
2) A needs to loop while waiting. So if your boolean variable was called isDone, and was set to true by threadB, then threadA should have some code like this:
synchronized(b) {
System.out.println("Waiting for b to complete...");
while( ! isDone ) b.wait();
}
In this particular case, there's actually no reason to have the synchronized block in A - since threadB doesn't do anything after it finishes running, and A doesn't do anything except wait for B, threadA could simply call b.join() to block until it finishes. I assume that your actual use case is more complex than this.
Why to make that complex ? Just use join() function of Thread.
ThreadB b = new ThreadB();
b.start();
b.join();
// now print b.total
do not synchronized(thread), don't do it, do not synchronized(thread).. repat: no synchronized(thread) :)
And if you need to wait for the thread 'b' to finish, use b.join(), now your code is free to hang in b.wait()
--
Hopefully the source below can grant you an insight while sync(thread)/notify() I consider bad practice. (cut-cut)
Enjoy
To proceeed below you make sure you have accepted Oracle's License aggreement, found there:
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewLicense-Start?LicenseUUID=7HeJ_hCwhb4AAAEtmC8ADqmR&ProductUUID=pGqJ_hCwj_AAAAEtB8oADqmS&cnum=&evsref=&sln=
Java sources (incl), called in init(), effectively called by any java c-tor, since java 1.5
private static **synchronized int** nextThreadNum() {
return threadInitNumber++;
}
//join (the method w/ nanos only increase millis by one, if nanos>500000, millis==0 and nanos>0
public final **synchronized** void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
public **synchronized** void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
//stop1 is called after stop ensures proper priviledges
private final **synchronized** void stop1(Throwable th) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if ((this != Thread.currentThread()) ||
(!(th instanceof ThreadDeath))) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW"
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
stop0(th);
} else {
// Must do the null arg check that the VM would do with stop0
if (th == null) {
throw new NullPointerException();
}
// Remember this stop attempt for if/when start is used
stopBeforeStart = true;
throwableFromStop = th;
}
}

Scanner(System.in) - how to cancel/skip input waiting

I am just wondering how to control console inputs in separate threads?
I have thread A and thread B and thread C; B and C they both control user input... the thing is I am not pretty sure how to switch between B and C threads the scanIn.nextLine(); because B seems to loop two unnecessary iterations before thread C can interrupt B :(
Main thread:
public class Main
{
private volatile ThreadGroup threadGroup=new ThreadGroup();//contains concurrent hash map...
private volatile TaskManager taskManager=new TaskManager(threadGroup);
private A a=new A(threadGroup);
private B b=new B(threadGroup,taskManager);
private C c=new C(threadGroup);
Main()
{
b.start();
threadGroup.add(a,"A");
threadGroup.add(b,"B");
threadGroup.add(c,"C");
}
public static void main(String args[]){new Main();}
}
TaskManager method snippet:
...
public synchronized void threadCMaybeCanBeStartedLater()
{
this.getThreadGroup().get("A").start();
}
...
thread A code like a (overridden run method invokes):
public void loopIt()
{
Random generator = new Random();
A: while(!this.interrupted())
{
Thread.sleep(1000);
int i=generator.nextInt(100)+1;
int j=generator.nextInt(100)+1;
if(i==j){this.invokeC(); System.out.println("event : i==j");}
}
}
private void invokeC()
{
if(!this.getThreadGroup().get("C").isAlive())this.getThreadGroup().get("C").start();
}
thread B code like a:
public void loopIt() throws InterruptedException
{
Scanner scanIn = new Scanner(System.in);
B: while(!this.isInterrupted())
{
Thread.sleep(1000);
String command= scanIn.nextLine();
...
if(command.equals("a"))
{
System.out.println("a was entered");
this.getTaskManager().threadCMaybeCanBeStartedLater();//
continue;
}
if(command.equals("b"))
{
System.out.println("b was entered");
continue;
}
if(command.equals("c"))
{
System.out.println("c was entered");
continue;
}
else{System.out.println("no such command");}
}
}
thread C (the run method invokes)
public void loopIt() throws InterruptedException
{
getThreadGroup().get("B").interrupt();
Scanner scanIn = new Scanner(System.in);
C: while(!this.isInterrupted())
{
Thread.sleep(1000);
String command= scanIn.nextLine();
...
if(command.equals("d"))
{
System.out.println("d was entered");
continue;
}
if(command.equals("e"))
{
System.out.println("e was entered");
this.interrupt();
break C;
}
if(command.equals("f"))
{
System.out.println("f was entered");
continue;
}
else{System.out.println("no such command");}
}
getThreadGroup().get("B").start();
}
...as you can see, the major code conception (see A thread snippet) is "you don't know when thread C can be started but when it started you need to give it console"; that's all; if it was GUI there was no problem but console-like app makes it quite problematic...
So the question is ... how to interrupt/re-start thread B immediately from thread C in this case?
Thanks
Synchronising Threads Using Thread Class
Thread.interrupt() on its own does not synchronise logic & timing between two threads.
Thread.interrupt() signals that the caller would like the thread to interrupt at a time in the near future. The interrupt() method sets an interrupt flag. The isInterrupted() method checks whether this flag is set (& also clears the flag again). The methods Thread.sleep(), Thread.join(), Object.wait() and a number of I/O methods also check & clear this flag, when throwing InterruptedException.
The thread doesn't immediately pause but continues running code. The internal thread logic is designed & implemented by the developer: continue to run thread code considered atomic/urgent until it gets to an "interruptable point", then check the interrupted flag / catch InterruptedException & then do a clean pause - usually via Thread.sleep(), Thread.join() or Object.wait(), and sometimes by exiting Thread.run() altogether thus stopping the thread permanently.
While all of this is happening the calling thread is still running and will execute an indeterminate amount of code before the interrupt takes effect... hence the lack of synchronisation. There is a lack of guaranteed happens-before condition between the code in one thread and code in the other thread.
Some approaches that do synchronise logic & timing between two threads (creating a happens-before condition):
thread1 calls Thread2.join()
thread1 calls SomeObject.wait() and thread2 calls SomeObject.notify()
Synchronise on a method or block
Quick Review of Your Code:
Thread B runs in an infinite loop - there is no call to interrupt it from any thread and no call for it's thread to wait(). It will, however, temporily block until System.in has more input, and then continue.
Thread A only interrupts itself - cleaner and easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (i != j)
Thread A only interrupts itself - cleaner and much easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (!"e".equals(command))
Thread C must make the following calls at the top of it's while loop:
threadB.interrupt();
synchronized(this) {
try {
this.wait();
} catch (InterruptedException ie) {
}
Thread B must make the following call as the last line of code:
synchronized(threadC) {
threadC.notify();
}
Reading from I/O (nextLine()) is a blocking & interruptable operation. Right next to it you introduce Thread.sleep() which is also a blocking & interruptable operation that introduces an artificial delay in your code - it is not necessary; remove.
The only Scanner method you call is nextLine(). You're using it as if it were an InputStreamReader & not doing any scanning. Also, you're not buffering input. If code stays like this, replace 'Scanner scanIn = Scanner(System.in)' with: 'BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))'.
The only ThreadGroup method you call are add() and get(). You're using it as if it were a HashMap & not doing any thread group management. If code stays like this, you may replace 'ThreadGroup' with 'HashMap'. However, even the HashMap seems excessive - could simply pass Threads references to other Threads using constructors/setters and avoid HashMap altogether.
Avoid excessive use of continue inside loops - try to avoid altogether. Best to do this by chaining successive 'if' statements together using '} else if {'...
Potential race condition between main thread and thread B. When thread B is started (from Main()) it may execute many lines of code before the main thread executes any more code - B may call ThreadGroup.get() before main thread has called ThreadGroup.add() x 3. Solution: in Main(), put b.start() after ThreadGroup.add() x 3
In general, "a".equals(command) is better practice than command.equals("a") - it handles nulls, giving correct result without NPE (you seem lucky here - probably won't have nulls).
Suggested Changes:
public class ThreadA extends Thread {
ThreadC threadC;
public void setThreadC(ThreadC threadC) {
this.threadC = threadC;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
Random generator = new Random();
int i, j;
do {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
i=generator.nextInt(100)+1;
j=generator.nextInt(100)+1;
} while (i != j);
threadC.start();
}
}
public class ThreadB extends Thread {
ThreadA threadA;
ThreadC threadC;
public void setThreadA(ThreadA threadA) {
this.threadA = threadA;
}
public void setThreadC(ThreadC threadC) {
this.threadC = threadC;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
// loop until interrupted
try {
while (!this.isInterrupted()) {
command = reader.readLine();
if ("a".equals(command)) {
System.out.println("a was entered");
if (threadA.getState() == Thread.State.NEW) {
threadA.start();
}
} else if ("b".equals(command)) {
System.out.println("b was entered");
} else if ("c".equals(command)) {
System.out.println("c was entered");
} else if ("z".equals(command)) {
System.out.println("z was entered");
throw new InterruptedException("Command z interruption");
} else {
System.out.println("no such command");
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
}
// Now notify ThreadC - it will wait() until this code is run
synchronized(threadC) {
threadC.notify();
}
}
}
public class ThreadC extends Thread {
ThreadB threadB;
public void setThreadB(ThreadB threadB) {
this.threadB = threadB;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
// Block until the lock can be obtained
// We want thread B to run first, so the lock should be passed into Thread C constructor in an already locked state
threadB.interrupt();
synchronized(this) {
try {
// Put this thread to sleep until threadB calls threadC.notify().
//
// Note: could replace this line with threadB.join() - and remove
// from threadB the call to threadC.notify()
this.wait();
} catch (InterruptedException ie) {
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
while (!"e".equals(command)) {
try {
command= reader.readLine();
if ("d".equals(command)) {
System.out.println("d was entered");
} else if ("e".equals(command)) {
System.out.println("e was entered");
} else if ("f".equals(command)) {
System.out.println("f was entered");
} else if ("z".equals("command")) {
System.out.println("z was entered");
} else {
System.out.println("no such command");
};
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}
nextLine() does not respond to interruption. You want to do something like
String command;
if (scanIn.hasNextLine())
command = scanIn.nextLine();
else
Thread.sleep(1000);
You can use flag variables (as global variables) to control the while loop in each thread...
suppose that Thread A has an infinite loop like this
while(true)
while(x == 1){
your code ...
}
Thread.sleep(2000);
}
when Thread b is started you can change x to 0 (suppose x is a global variable) then when Thread b finishes executing change x to 1 at the end of Thread b code...
or you can interrupt the thread from thread itself based of flag value x

Categories

Resources