人品不好 iteye上面问了,但是连帖子都找不到了,真心无语 第二次了,大牛们给说说我这代码啥问题,
按理说ExecutorService的shutDownNow会吧所有正在执行的任务给中断(调用interrupt), 但事实并非如此,是不是
我哪里理解错了,我对已提交的任务返回的Future调用cancel也不行,只有同时shutDownNow和cancel一起调用才可以正常退出R1
package com.thread;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;class R2 implements Runnable {
Runnable r; public R2(Runnable r) {
this.r = r;
} @Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (r) {
r.notifyAll();
}
System.out.println("R2 over");
}}public class R1 implements Runnable { @Override
public void run() {
boolean b = false;
synchronized (this) {
while (!(b = Thread.interrupted())) {
try {
wait();
System.out.println("R1 awakend");
} catch (InterruptedException e) {
System.out.println("InterruptedException, interu:" + b);
}
}
System.out.println("R1 over, interrupted:" + b);
} } public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
Runnable r1 = new R1(); Future<?> f = exec.submit(r1);
exec.execute(new R2(r1)); TimeUnit.SECONDS.sleep(2);
exec.shutdownNow();
 
 /*boolean ret = f.cancel(true);
 System.out.println("main cancel:" + ret );*/ }
}

解决方案 »

  1.   

    刚才我细细的读了下Thinking In Iava并发这章的任务终结,这里有句很关键的话“当跑出异常或是该任务调用Thread.interrupted(),中断状态会被复位”也就是说,我们在调用Thread.currentThread().isInterrupted()或者是Thread.interrupted()得到的都是false,所以用我上述的方法来做为while循环结束的标识不好,当然也不建议让异常机制来控制执行流程,所以建议用一个标志位来跳出循环,有不同意见的大家可以一起讨论交流。
      

  2.   

    不知道LZ有没有看过Object类的wait方法的API:抛出: 
    IllegalMonitorStateException - 如果当前的线程不是此对象监视器的所有者。 
    InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,另一个线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除
    也就是说,从wait中断后,中断标记就被清掉了,while里的那个条件自然一直返回false
      

  3.   

    Read the API specifications for Thread.interrupt() -Interrupts this thread.Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.If none of the previous conditions hold then this thread's interrupt status will be set.Interrupting a thread that is not alive need not have any effect.So, all that will happen is the thread's interrupt status will be set.EDITIf you read the API specifications for Object.wait(), you'll see the following -Throws:InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.
      

  4.   

    看一下这个吧:
    wait
    public final void wait()
                    throws InterruptedException在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。 
    当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。 对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用: synchronized (obj) {
    while (<condition does not hold>)
    obj.wait();
    ... // Perform action appropriate to condition
         }
     此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。 抛出: 
    IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。 
    InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
      

  5.   

    R1这么改下也可以执行下去,楼上几个提到的我也注意到了,现在的疑惑是,我的try catch能影响到线程状态的清除?public class R1 implements Runnable {    @Override
        public void run() {
            boolean b = false;
            try {
                synchronized (this) {
                    while (!(b = Thread.interrupted())) {
                        wait();
                        System.out.println("R1 awakend");
                    }
                }
            } catch (InterruptedException e) {
                System.out.println("InterruptedException, interu:" + b);
            }
            System.out.println("R1 over, interrupted:" + b);
        }
      

  6.   

    我自己来回吧,谢谢楼上几位热心兄弟,希望对后面的人有用,其实这个问题如果拆分成几个小问题,知道异常处理机制和看看wait API说明都能回答我的7楼的问题,先看下代码
    Java代码  
    public void run() {  
            boolean b = false;  
            // try catch放到这里是ok的  
            try {  
                while (!(b = Thread.currentThread().isInterrupted())) {  
                    synchronized (this) {  
                        // try {  
                        wait();  
                        System.out.println("R1 awakend");  
                        // } catch (InterruptedException e) {  
                        // System.out.println("InterruptedException, interu:"  
                        // + Thread.currentThread().isInterrupted());  
                        // }  
                    }  
                }  
            } catch (InterruptedException e) {  
                System.out.println("InterruptedException, interu:"  
                        + Thread.currentThread().isInterrupted());  
            }  先说下Java异常处理流程,try块中有异常,直接掉到catch中执行,无论异常代码下面是否还有课执行的代码都不执行了,直接到catch。恩 明白这里我们看下上面代码,我把try catch放到了while循环里,catch执行完了孩子while里面,由于抛出了异常,wait API说的很清楚,中断状态会被清除,so,intterrupted返回false是必然的,但我把try catch放到while外面,很明显,catch执行完成了,就不会在回到while循环了,so,结果你懂得,并没我提问想的这么复杂。
      

  7.   

    try{
        while(...){
            try{
            ...
            }//??没catch
        }
    }catch(...){
        ...
    }
    这结构看着别扭啊
      

  8.   

    catch块里加上一句也可以:
                        Thread.currentThread().interrupt();//