可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I was reading this post and the suggestions given to interrupt one thread from another is
" " " Here are a couple of approaches that should work, if implemented correctly.
You could have both threads
regularly check some common flag variable (e.g. call it stopNow), and arrange that both threads set it when they finish. (The flag variable needs to be volatile ... or properly synchronized.)
You could have both threads
regularly call the Thread.isInterrupted() method to see if it has been interrupted. Then each thread needs to call Thread.interrupt() on the other one when it finishes." " "
I do not understand how the second approach is possible that is using Thread.isInterrupted()
. That is, how can Thread-1
call Thread.interrupt()
on Thread-2
.
Consider this example, in the main method I start two threads
t1
and t2
. I want t1
to stop t2
after reaching certain condition. how can I achieve this?
class Thread1 extends Thread { public void run(){ while (!isDone){ // do something } } //now interrupt Thread-2 } class Thread2 extends Thread { public void run(){ try { while(!Thread.isInterupted()){ //do something; } catch (InterruptedExecption e){ //do something } } } public class test { public static void main(String[] args){ try { Thread1 t1 = new Thread1(); Thread2 t2 = new Thread2(); t1.start(); t2.start(); } catch (IOException e) { e.printStackTrace(); } } }
回答1:
The context of this is that you are trying to implement your scheme using thread interrupts.
In order for that to happen, the t1
object needs the reference to the t2
thread object, and then it simply calls t2.interrupt()
.
There are a variety of ways that t1
could get the reference to t2
.
- It could be passed as a constructor parameter. (You would need to instantiate Thread2 before Thread1 ...)
- It could be set by calling a setter on Thread1.
- It could be retrieved from a static variable or array, or a singleton "registry" object of some kind.
- It could be found by enumerating all of the threads in the ThreadGroup looking for one that matches
t2
's name.
回答2:
public class test { private static boolean someCondition = true; public static void main(String[]args){ Thread t2 = new Thread(new someOtherClass("Hello World")); Thread t1 = new Thread(new someClass(t2)); t2.start(); t1.start(); try { t1.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } static class someClass implements Runnable{ Thread stop; public someClass(Thread toStop){ stop = toStop; } public void run(){ while(true){ try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(someCondition && !stop.isInterrupted()){ stop.interrupt(); } } } } static class someOtherClass implements Runnable{ String messageToPrint; public someOtherClass(String s){ messageToPrint = s; } public void run(){ while(true){ try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(messageToPrint); } } }
}
回答3:
You could consider the use of Future
interface. It provides a cancel()
method. http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html
回答4:
Playing with interruption makes your life unnecessarily hard. Besides the fact that your code must know the threads, interruption does not provide any context information about the reason of the interruption.
If you have a condition that is shared by your code possibly executed by different threads, just encapsulate that condition into an object and share that object:
public class Test { public static void main(String[] args) { Condition c=new Condition(); new Thread(new Setter(c)).start(); new Thread(new Getter(c, "getter 1")).start(); // you can simply extend it to more than one getter: new Thread(new Getter(c, "getter 2")).start(); } } class Getter implements Runnable { final Condition condition; final String name; Getter(Condition c, String n) { condition=c; name=n; } public void run() { while(!condition.isSatisfied()) { System.out.println(name+" doing something else"); try { Thread.sleep(300); } catch(InterruptedException ex){} } System.out.println(name+" exiting"); } } class Setter implements Runnable { final Condition condition; Setter(Condition c) { condition=c; } public void run() { System.out.println("setter: doing my work"); try { Thread.sleep(3000); } catch(InterruptedException ex){} System.out.println("setting condition to satisfied"); condition.setSatisfied(); } } class Condition { private volatile boolean satisfied; public void setSatisfied() { satisfied=true; } public boolean isSatisfied() { return satisfied; } }
The big advantage of this encapsulation is that it is easy to extend. Suppose you want to allow a thread to wait for the condition instead of polling it. Taking the code above it’s easy:
class WaitableCondition extends Condition { public synchronized boolean await() { try { while(!super.isSatisfied()) wait(); return true; } catch(InterruptedException ex){ return false; } } public synchronized void setSatisfied() { if(!isSatisfied()) { super.setSatisfied(); notifyAll(); } } } class Waiter implements Runnable { final WaitableCondition condition; final String name; Waiter(WaitableCondition c, String n) { condition=c; name=n; } public void run() { System.out.println(name+": waiting for condition"); boolean b=condition.await(); System.out.println(name+": "+(b? "condition satisfied": "interrupted")); } }
Without changing the other classes you can now extend your test case:
public class Test { public static void main(String[] args) { WaitableCondition c=new WaitableCondition(); new Thread(new Setter(c)).start(); new Thread(new Getter(c, "getter 1")).start(); // you can simply extend it to more than one getter: new Thread(new Getter(c, "getter 2")).start(); // and you can have waiters new Thread(new Waiter(c, "waiter 1")).start(); new Thread(new Waiter(c, "waiter 2")).start(); } }