I have a method, wich supposed to interrupt a thread, but it's not. Do I need to always check the thread interrupted in the while method to stop the thread? How can I just terminate the thread at anytime?
solverTh = new Thread(new Runnable() {
#Override
public void run() {
while(somethingistrue){
//do lot of stuff here for long time
}
}
});
solverTh.start();
}
public void terminate(){
if(solverTh != null){
solverTh.interrupt();
}
}
okay than I thought the "lot of stuff" is irrelevant, but I will post it than. It makes openGL operations, I added the boolean variable "terminated" to the code it works now, I just wanted to find a nicer solution:
(glc is a GLCanvas, and the rotmultiplecube method rotates 3 objects)
Anyways I've solved the problem now, thanks for the answers.
terminated = false;
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(BruteForce.class.getName()).log(Level.SEVERE, null, ex);
}
int colorToBeSolved = Statics.RED_BLUE_TABLE[stateToBeSolved];
System.out.println(stateToBeSolved + "," + colorToBeSolved);
if(entities[0].getColor() != colorToBeSolved){
if(terminated) return;
fullRotate(Statics.FIRST_ROW, Statics.DOWN);
}
if(entities[1].getColor() != colorToBeSolved){
if(terminated) return;
fullRotate(Statics.SECOND_COL, Statics.RIGHT);
}
if(entities[2].getColor() != colorToBeSolved){
if(terminated) return;
fullRotate(Statics.THIRD_COL, Statics.RIGHT);
}
if(entities[3].getColor() != colorToBeSolved){
if(terminated) return;
fullRotate(Statics.SECOND_ROW, Statics.DOWN);
}
if(entities[6].getColor() != colorToBeSolved){
if(terminated) return;
fullRotate(Statics.THIDR_ROW, Statics.DOWN);
}
for(int i = 0; i < 9; ++i){
int col = i % 3;
int row = 3 + i/3;
while(entities[i].getState() != stateToBeSolved){
for(int j = 0;j < 2; ++j){
if(entities[i].getState() != stateToBeSolved){
if(terminated) return;
fullRotate(col, Statics.LEFT);
if(terminated) return;
fullRotate(row, Statics.UP);
if(terminated) return;
fullRotate(col, Statics.RIGHT);
if(terminated) return;
fullRotate(row, Statics.DOWN);
}
}
for(int j = 0;j < 2; ++j){
if(entities[i].getState() != stateToBeSolved){
if(terminated) return;
fullRotate(col, Statics.RIGHT);
if(terminated) return;
fullRotate(row, Statics.UP);
if(terminated) return;
fullRotate(col, Statics.LEFT);
if(terminated) return;
fullRotate(row, Statics.DOWN);
}
}
}
}
}
and the fullrotate method:
private void fullRotate(int selectionIndex, int direction){
for(int i = 0; i < 9; ++i){
glc.rotMultipleCubeSlow(selectionIndex, direction);
try {
Thread.sleep(20);
} catch (InterruptedException ex) {
terminate();
}
}
glc.setMovesText(selectionIndex, direction);
glc.setMultipleStateAndColorsByTable(selectionIndex, direction);
glc.isEntitiesRight();
}
while(somethingistrue !Thread.currentThread().isInterrupted()){
//do lot of stuff here for long time
}
Does not have to work for blocking IO. Use dirty tricks: override Thread.interrupt() close IO object, cause IOException that if properly handled may end thread run method.
The elegant solution is to modify your fullRotate() method to throw InterruptedException.
private void fullRotate(int selectionIndex, int direction)
throws InterruptedException{
for(int i = 0; i < 9; ++i){
glc.rotMultipleCubeSlow(selectionIndex, direction);
Thread.yield();
}
glc.setMovesText(selectionIndex, direction);
glc.setMultipleStateAndColorsByTable(selectionIndex, direction);
glc.isEntitiesRight();
}
When you call Thread.interrupt() you cause InterruptedException when any of the methods that throw it is invoked, in your case the Thread.sleep() or Thread.yield(). This means that the best approach is to use it to actually interrupt the calculation.
You still need to check Thread.currentThread().isInterrupted() if you want immediate response to your Thread.interrupt()
You can ether remove if(terminated) return; or substitute it with Thread.currentThread().isInterrupted() check. Removing will be fine because the Thread.sleep(20)/Thread.yield() from fullRotate() will throw the InterruptedException. Also code will be cleaner without all these if(terminated) all over the place.
Use Thread.yield() instead for Thread.sleep(20). Obviously you don't want to sleep, because you put 20 millis. 20 milis is very close to the context switch time quantum. The thread will ether sleep more, or less. You don't want it to sleep more without any reason, so use yield().
Your thread run() then becomes:
solverTh = new Thread(new Runnable() {
#Override
public void run() {
while(somethingistrue &&
!Thread.currentThread().isInterrupted()) {
try {
//do lot of stuff here for long time
} catch (InterruptedException ex) {
// handle stop processing
}
}
}
});
solverTh.start();
Also you have to remove the try catch from the following:
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(BruteForce.class.getName()).log(Level.SEVERE, null, ex);
}
The only way to interrupt thread is to make it exit itself. Strightforward interruption is not even implemented in Java because of deadlocks possibility. So your thread code must look like:
solverTh = new Thread(new Runnable() {
#Override
public void run() {
while(somethingistrue)
// Do a little stuff here
}
}
});
solverTh.start();
And somethingistrue is a kind of a signal for thread to interrupt.
When a thread is running ( consuming CPU cycles ) , then it will not by default ( automatically ) respond to Thread.interrupt(). You will have to write the code to do this explicitly.
Break up //do lot of stuff here for long time into 2 or more steps , and insert between these steps checks for the Thread.currentThread().isInterrupted() - if true - break out , else continue. This is only safe way to achieve what you want.
It depends on what the long running stuff is, you will have to design the steps and decide when its best to check for interruption and breakout.
The only thing that can reliably stop the execution of one thread from another is the OS. So, there are not many choices:
1) Signal the thread to stop itself. This scheme kinda depends on what the thread is doing. If it's running on another processor or stuck on a blocking call you cannot unblock, (note-many blocking calls can be persuaded to return early), there can be problems.
What is 'lot of stuff' doing?
2) Use an OS call to terminate the thread. This can be a viable option, depending on what the thread does. If there is any possibility of terminating the thread while it holds a public lock on a vital resource, (eg. it's in the middle of a malloc() and has the memory-manager locked), then you can get into trouble. You have to be sure of what thread is doing to safely abort it in this way.
3) Use a separate process to run the 'stuff'. This will obviously work OK, but usually involves slow and painful inter-process comms to pass data and return results.
4) Design the app so that it does not need to terminate the thread. Some apps never need to terminate any threads except at app shutdown, so there's no problem - the OS can stop anything. In those cases where a thread must be 'stopped' during an app run and is running a lengthy CPU-intensive operation or is blocked for a long and possibly indeterminate period, 'orphaning' a thread by setting its priority to minimum/idle and just leaving it to eventually die off is another common approach.
The worst possible scenario is a thread running a lot of stuff for long time that uses the memory-manager or other public locks, possibly in a library where you don't know exactly what it's doing, can't be hooked and reads/writes data in such a way that 'orphaning' it off means that another thread cannot be started to use the data. You're really stuft then and you may have to terminate the app and restart. It's just best to avoid designs where a thread can get into such a state :)
5) Forgot one - if the thread is using data you can get at, setting something to NULL, 0, MaxInt or some other like bodge can cause an exception to be raised in the thread running the long stuff. When execution bubbles out of long stuff, the thread can check the Interrupted state in the exception handler and exit if set.
Related
I have some class:
#Component
public MyClass {
private volatile boolean stopped = false;
public void verification() throws Exception {
Thread kpiAllThread = getKPIAllThread();
try {
for (int i = 0; i < poolSize; i++) {
execDispatcher.put(processExecutor.submit(getCheckValuesInKPIConsumerTask(workingQueue)));
}
kpiAllThread.start();
} finally {
waitFinished();
}
}
public void setStop(bolean stopped) {
this.stopped = stopped;
}
private Thread getKPIAllThread() {
return new Thread(() -> {
try {
LOG.debug("KPIAllThread started!");
dao.getKpiAll(workingQueue);
for (int i = 0; i < poolSize; i++) {
workingQueue.put(() -> true);
}
} catch (Exception ex) {
LOG.error("KPIAllThread exception: ", ex);
} finally {
LOG.error("KPIAllThread finished!");
}
});
}
}
This class starts the producer thread getKPIAllThread. He get data from db and put in BlockingQueue.
Method getKpiAll like this:
public void getKpiAll(final BlockingQueue<KeyPropertyIndex> kpiData) throws Exception {
LOG.debug("Starting getKpiAll");
try (final Connection con = dataSource.getConnection();
final Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
stmt.setFetchSize(Integer.MIN_VALUE);
try (final ResultSet rs = stmt.executeQuery(sqlGetAllkpi)) {
while (rs.next()) {
kpiData.put(new KeyPropertyIndexData(rs.getLong(1), rs.getString(2)));
}
}
LOG.debug("Finished get getKpiAll");
} catch (Exception ex) {
throw ex;
}
}
There is also a variable stopped that can be set from outside to true. How can I safely stop my thread while doing so? So that all connections to the database are closed and the thread is successfully completed?
The cleanest and safest rule for stopping a thread is that the code running in thread should periodically check a condition (say, boolean shouldExit()). When the code detects that this condition is true, it should stop doing what is doing and terminate.
The code running in thread should check this condition fairly often so that it can react reasonably fast. As a rule of thumb, the thread should exit less than one second after you set this condition. The check would typically look something like if (shouldExit()) break somewhere in your for-loop that iterates over pool size. However, dao.getKpiAll(workingQueue) looks potentially long, so you might place more checks inside getKpiAll.
When you have this checking in place, you must ensure that your code will exit cleanly every time the condition becomes true. For example, you can use finally blocks to close any connections etc. If this happens during getKpiAll, there is no sense to even continue with for loop to process items and so on.
Sometimes, this can get more tricky - i.e. when the thread is waiting on a network operation, you might need to close the network socket or something like that to interrupt it. In any case, avoid using Thread.stop() or Thread.interrupt() - see documentation why they are problematic.
If you do things like this, you can set the condition from outside the thread at any time to request the thread to terminate. You can make something like void requestExit() and set a boolean variable there. After calling requestExit(), you call Thread.join() with a suitable timeout to wait for the thread to do its business, check the condition and exit. Again, as a rule of thumb, make the timeout 3-10 times as long as the longest reaction time of your thread.
It looks that you already have setStopped(boolean stopped) for that purpose, but you're not checking it. First, I would remove parameter stopped because it doesn't make sense to pass false to it. Second, you need to add checks as described above. You might want to make this variable visible to dao - just remember that it's much better to expose it as a synchronized boolean method than as a boolean field.
I just started out with threading. I wrote a main class that sets up and starts 100 threads, waits 5 seconds and then interrupts them (at least that's what I thought it did):
public static void main(String[] args) {
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new Walker());
threads.add(t);
}
System.out.println("Starting threads...");
for (Thread thread : threads) {
thread.start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// don't do anything
}
System.out.println("Time's up - Terminating threads...");
for (Thread t : threads) {
t.interrupt();
System.out.print(".");
}
for (Thread t : threads) {
try {
t.join(10);
} catch (InterruptedException e) {
// don't do anything
}
}
System.out.println("");
System.out.println("All done.");
}
The threads looked a bit like this:
public class Walker implements Runnable {
public void run() {
for (int i = 0;; i++) {
//do some complicated stuff that takes some time
System.out.println(Thread.currentThread().getName() + ":" + i);
if (Thread.interrupted()) {
break;
}
}
}
}
Now, the output I got was that the main thread began interrupting threads, but some sub threads continued to run a few times (i.e. loop iterations) before terminating, e.g.
Starting threads...
Thread-1:0
Thread-2:0
Thread-1:1
Thread-3:0
[...]
Time's up - Terminating threads...
......Thread-1:60
Thread-1:61
...Thread-1:62
Thread-2:55
..All done.
[output from threads sometimes continued even here - after the join()]
At that time I didn't fully understand that a single thread could be allocated enough processor time to run a few times - I expected at most one additional run before the main thread had the opportunity to interrupt it.
But while I now see that it is absolutely fine for a thread to be executed for some (long) time before the main thread gets a chance to terminate (i.e. interrupt) it, I am still wondering: is there an easy way to interrupt all child threads in a timely manner from the main thread? (Setting a "time to live" through a thread's constructor and then testing inside the Walker class for it is not what I want.)
Also: is it possible for the last print statement to execute and then see some output from individual threads - after all threads were join()ed? (Maybe I have a glitch somewhere else; the actual code is a bit more complex...)
The problem you observe is probably due to how System.out.println works. It is a synchronized method. So a likely explanation is:
when calling System.out.print("."); after t.interrupt();, your main thread acquires the lock to print
before the lock is released, worker threads arrive at System.out.println(Thread.currentThread().getName() + ":" + i); and wait for the lock
when the main thread releases the lock, all the worker threads that were waiting print their progress.
the main thread arrives at System.out.print("."); again and has to wait for the print lock to be available, etc.
Regarding the fact that you see more prints from the worker threads after "All Done" is printed: you only join for 10 ms, so it is possible that it is not enough and a thread is not finished within 10ms of being interrupted. If you just use join() you should not see that any longer.
Example of Worker class that reproduces the behaviour you observe:
class Walker implements Runnable {
public void run() {
for (int i = 0;; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
//do not respond to interruption too quickly on purpose
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + ":" + i);
if (Thread.interrupted()) {
break;
}
}
}
}
It would be easier with ExecutorService, eg
int nThreads = 100;
ExecutorService ex = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < nThreads; i++) {
ex.execute(new Walker());
}
Thread.sleep(5000);
ex.shutdownNow();
Maybe I have a glitch somewhere else; the actual code is a bit more complex...
Yes it is a glitch, unfortunately isn't a simple set 1 property, java side.
If the code is commercial, complex, than you can allocate a bit more time to write some native libraries, for major Os type. With that help you can easily play with threads as you wanted.
The first times has an overhead for developing and understanding how the threads are woking in native, os side, than just call a function with a few params :)
Not sure, if is helping, the glitch exists.
I'm writing a game engine which performs alhpa-beta search on at a game state, and I'm trying to parallelize it. What I have so far is working at first, and then it seems to slow to a halt. I suspect that this is because I'm not correctly disposing of my threads.
When playing against the computer, the game calls on the getMove() function of a MultiThreadedComputerPlayer object. Here is the code for that method:
public void getMove(){
int n = board.legalMoves.size();
threadList = new ArrayList<WeightedMultiThread>();
moveEvals = new HashMap<Tuple, Integer>();
// Whenever a thread finishes its work at a given depth, it awaits() the other threads
// When all threads are finished, the move evaluations are updated and the threads continue their work.
CyclicBarrier barrier = new CyclicBarrier(n, new Runnable(){
public void run() {
for(WeightedMultiThread t : threadList){
moveEvals.put(t.move, t.eval);
}
}
});
// Prepare and start the threads
for (Tuple move : board.legalMoves) {
MCBoard nextBoard = board.clone();
nextBoard.move(move);
threadList.add(new WeightedMultiThread(nextBoard, weights, barrier));
moveEvals.put(move, 0);
}
for (WeightedMultiThread t : threadList) {t.start();}
// Let the threads run for the maximum amount of time per move
try {
Thread.sleep(timePerMove);
} catch (InterruptedException e) {System.out.println(e);}
for (WeightedMultiThread t : threadList) {
t.stop();
}
// Play the best move
Integer best = infHolder.MIN;
Tuple nextMove = board.legalMoves.get(0);
for (Tuple m : board.legalMoves) {
if (moveEvals.get(m) > best) {
best = moveEvals.get(m);
nextMove = m;
}
}
System.out.println(nextMove + " is the choice of " + name + " given evals:");
for (WeightedMultiThread t : threadList) {
System.out.println(t);
}
board.move(nextMove);
}
And here run() method of the threads in question:
public void run() {
startTime = System.currentTimeMillis();
while(true) {
int nextEval = alphabeta(0, infHolder.MIN, infHolder.MAX);
try{barrier.await();} catch (Exception e) {}
eval = nextEval;
depth += 1;
}
}
I need to be able to interrupt all the threads when time is up-- how am I supposed to implement this? As of now I'm constantly catching (and ignoring) InterruptedExceptions.
Thread.stop was deprecated for a reason. When you interrupt a thread in the middle, the thread doesn't have the chance to properly release resources it was using, and doesn't notify other threads of its completion...something that's very important in multi-threaded apps. I'm not surprised your performance tanks; I would be willing to bet your memory usage shoots through the roof. You also don't recycle the threads, you start and stop them without creating new objects, which means whatever broken state the variables were left in is probably still plaguing them.
A better way is to set a flag that tells the thread it should return. So include in your WeightedMultiThread class a boolean named something like shouldQuit, and set it to false every time start() is called. Then, instead of while (true) do while (!shouldQuit), and instead of t.stop(), use t.shouldQuit = true. After you do that to every thread, have another loop that checks each thread for t.isAlive(), and once every thread has returned, go about your business. You should have much better results that way.
This looks like an ideal place to use an ExecutorService. You can create Callable instances that implement the parallel tasks, submit them to the ExecutorService, then use awaitTermination to enforce a timeout.
For example:
public void getMove() {
ExecutorService service = Executors.newFixedThreadPool(board.legalMoves.size());
List<Future<Something>> futures = new ArrayList<Future<Something>>(board.legalMoves.size());
for (Tuple move : board.legalMoves) {
futures.add(service.submit(new WeightedMultiThread(...)));
}
service.awaitTermination(timePerMove, TimeUnit.MILLISECONDS);
service.shutdownNow(); // Terminate all still-running jobs
for (Future<Something> future : futures) {
if (future.isDone()) {
Something something = future.get();
// Add best move logic here
}
}
...
}
Replace Something with something that encapsulates information about the move that has been evaluated. I'd suggest Something be a class that holds the Tuple and its associated score. Your WeightedMultiThread class can do something like this:
class WeightedMultiThread implements Callable<Something> {
public Something call() {
// Compute score
...
// Return an appropriate data structure
return new Something(tuple, score);
}
}
Even better would be to create the ExecutorService once and re-use it for each call to getMove. Creating threads is expensive, so best to only do it once if you can. If you take this approach then you should not call shutdownNow, but instead use the Future.cancel method to terminate jobs that have not completed in time. Make sure your WeightedMultiThread implementation checks for thread interruption and throws an InterruptedException. That's usually a good way to write a long-running task that needs to be interruptible.
EDIT:
Since you're doing a level-by-level exploration of the game space, I'd suggest that you encode that in the getMove function rather than in the Tuple evaluation code, e.g.
public Tuple getMove() {
ExecutorService service = ...
Tuple best = null;
long timeRemaining = MAX_TIME;
for (int depth = 0; depth < MAX_DEPTH && timeRemaining > 0; ++depth) {
long start = System.currentTimeMillis();
best = evaluateMoves(depth, service, timeRemaining);
long end = System.currentTimeMillis();
timeRemaining -= (end - start);
}
return best;
}
private Tuple evaluateMoves(int depth, ExecutorService service, long timeRemaining) {
List<Future<Whatever>> futures = service.submit(...); // Create all jobs at this depth
service.awaitTermination(timeRemaining, TimeUnit.MILLISECONDS);
// Find best move
...
return best;
}
That could probably be cleaner, but you get the idea.
The most sensitive way is to use interruption mechanism. Thread.interrupt() and Thread.isInterrupted() methods. This ensures your message will be delivered to a thread even if it sits inside a blocking call (remember some methods declare throwing InterruptedException?)
P.S. It would be useful to read Brian Goetz's "Java Concurrency in Practice" Chapter 7: Cancellation and Shutdown.
Sorry for my bad formatting. I am using a notepad to write my programs.
This is a working code. The only question I have is, I have read that notify and wait must be used in a Synchornized block. However, in the following example, wait and notify are not used in a synchronized block and still no error is thrown.
class counthrd implements Runnable {
Thread thrd;
String x;
counthrd cnt1;
counthrd() {
}
boolean suspended;
boolean stopped;
counthrd(String s, counthrd cnt1) {
thrd = new Thread(this, s);
this.cnt1 = cnt1;
thrd.start();
x = s;
}
public void run() {
try {
System.out.println("Starting " + thrd.currentThread().getName());
for (int i = 1; i < 100; i++) {
System.out.print(i + " ");
if ((i % 10) == 0) {
System.out.println();
Thread.sleep(500);
}
//synchronized(cnt1){
while (suspended) {
System.out.println("going to wait mode");
wait();
notify();
}
//}
}
} catch (Exception e) {
System.out.println(e);
}
}
synchronized void suspendme() {
suspended = true;
notify();
}
synchronized void resumeme() {
suspended = false;
notify();
}
}
class counter {
public static void main(String args[]) throws InterruptedException {
counthrd cnt1 = new counthrd();
counthrd cnthrd1 = new counthrd("thrd 1", cnt1);
Thread.sleep(1000);
System.out.println("going to wait mode");
cnt1.suspendme();
Thread.sleep(1000);
System.out.println("resuming");
cnt1.resumeme();
Thread.sleep(1000);
}
}
See my comment. Since IllegalMonitorStateException is never thrown, we know that wait is never being called.
Notice you have two instances of counthrd...
counthrd cnt1 = new counthrd();
counthrd cnthrd1 = new counthrd("thrd 1", cnt1);
See which instance you're calling suspendme and resumeme on?
Thread.sleep(1000);
System.out.println("going to wait mode");
cnt1.suspendme();
Thread.sleep(1000);
System.out.println("resuming");
cnt1.resumeme();
Thread.sleep(1000);
cnt1 is initialized using your no-arg constructor, seen here:
counthrd() {
}
The point is that cnt1 never actually starts its own thread. It never does anything, really. cnthrd1 is the one that starts a thread, as seen here:
counthrd(String s, counthrd cnt1) {
thrd = new Thread(this, s);
this.cnt1 = cnt1;
thrd.start();
x = s;
}
The point to make is that suspended is an instance field, and not shared between cnt1 and cnthrd1. Modifying cnt1.suspended will not cause cnthrd1 to go into "wait mode". wait is never called, and thus the exception is never thrown.
To demonstrate, try calling suspendme and resumeme on cnthrd1, instead... :-)
C:\dev\scrap>javac counter.java
C:\dev\scrap>java counter
Starting thrd 1
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
going to wait mode
going to wait mode
java.lang.IllegalMonitorStateException
resuming
That being said, I figured I'd suggest you do some stuff that your code should be doing.
Declare suspended as volatile. Without some explicit memory ordering guarantees, there's no guarantee when or even if cnthrd1 reads the updated value of suspended.
Ditch the cnt1 field and instance; there's no reason for them. Get rid of that empty constructor, too.
Thread.currentThread is a static method; you don't need to use an instance for it. That all aside, thrd is guaranteed to equal Thread.currentThread here.
counthrd.x is equal to thrd.getName; why not just use x instead?
Use some better, more descriptive names. For example, instead of x, why not name? Instead of thrd, why not thread? Instead of counthrd, why not CountingThread?
You only need to call notify in resumeme, not suspendme. (in fact, calling notify in suspendme could accidentally trigger an InterruptedException if the thread is sleeping i.e. when (i % 10) == 0)
You also don't want notify in the while (suspended) loop. Your while loop can actually be turned into an if statement, too, now.
As previously stated, you need synchronized (this) around your code that calls while.
Avoid doing real logic in the constructor, e.g. thrd.start().
suspend doesn't need to be synchronized. resume doesn't need to be synchronized, either; only the wait and notify calls require it.
You can find a modified version of your example that works properly here.
I want to stop a running thread immediately. Here is my code:
Class A :
public class A() {
public void methodA() {
For (int n=0;n<100;n++) {
//Do something recursive
}
//Another for-loop here
//A resursive method here
//Another for-loop here
finishingMethod();
}
}
Class B:
public class B() {
public void runEverything() {
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
A a = new A();
a.methodA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
My problem is that i need to be able to stop the thread in Class B even before the thread is finished. I've tried interrupt() method, but that doesn't stop my thread. I've also heard about using shared variable as a signal to stop my thread, but I think with long recursive and for-loop in my process, shared-variable will not be effective.
Any idea ?
Thanks in advance.
Thread.interrupt will not stop your thread (unless it is in the sleep, in which case the InterruptedException will be thrown). Interrupting basically sends a message to the thread indicating it has been interrupted but it doesn't cause a thread to stop immediately.
When you have long looping operations, using a flag to check if the thread has been cancelled is a standard approach. Your methodA can be modified to add that flag, so something like:
// this is a new instance variable in `A`
private volatile boolean cancelled = false;
// this is part of your methodA
for (int n=0;n<100;n++) {
if ( cancelled ) {
return; // or handle this however you want
}
}
// each of your other loops should work the same way
Then a cancel method can be added to set that flag
public void cancel() {
cancelled = true;
}
Then if someone calls runEverything on B, B can then just call cancel on A (you will have to extract the A variable so B has a reference to it even after runEverything is called.
I think you should persevere with using Thread.interrupt(). But what you need to do to make it work is to change the methodA code to do something like this:
public void methodA() throws InterruptedException {
for (int n=0; n < 100; n++) {
if (Thread.interrupted) {
throw new InterruptedException();
}
//Do something recursive
}
// and so on.
}
This is equivalent declaring and using your own "kill switch" variable, except that:
many synchronization APIs, and some I/O APIs pay attention to the interrupted state, and
a well-behaved 3rd-party library will pay attention to the interrupted state.
Now it is true that a lot of code out there mishandles InterruptedException; e.g. by squashing it. (The correct way to deal with an InterruptedException is to either to allow it to propagate, or call Thread.interrupt() to set the flag again.) However, the flip side is that that same code would not be aware of your kill switch. So you've got a problem either way.
You can check the status of the run flag as part of the looping or recursion. If there's a kill signal (i.e. run flag is set false), just return (after whatever cleanup you need to do).
There are some other possible approaches:
1) Don't stop it - signal it to stop with the Interrupted flag, set its priority to lowest possible and 'orphan' the thread and any data objects it is working on. If you need the operation that is performed by this thread again, make another one.
2) Null out, corrupt, rename, close or otherwise destroy the data it is working on to force the thread to segfault/AV or except in some other way. The thread can catch the throw and check the Interrupted flag.
No guarantees, sold as seen...
From main thread letsvsay someTask() is called and t1.interrput is being called..
t1.interrupt();
}
private static Runnable someTask(){
return ()->{
while(running){
try {
if(Thread.interrupted()){
throw new InterruptedException( );
}
// System.out.println(i + " the current thread is "+Thread.currentThread().getName());
// Thread.sleep( 2000 );
} catch (Exception e) {
System.out.println(" the thread is interrputed "+Thread.currentThread().getName());
e.printStackTrace();
break;
}
}
o/P:
java.lang.InterruptedException
at com.barcap.test.Threading.interrupt.ThreadT2Interrupt.lambda$someTask$0(ThreadT2Interrupt.java:32)
at java.lang.Thread.run(Thread.java:748)
the thread is interrputed Thread-0
Only t1.interuuption will not be enough .this need check the status of Thread.interrupted() in child thread.