如何从监视器线程中断另一个线程

时间:2010-08-05 06:48:46

标签: java multithreading interrupt

我知道这是不明智的,但我仍然试图从另一个保持时间的线程中查找一个中断挂起的线程的方法。

我做的是: 我在即将发生可疑的网络操作之前​​启动监视器线程。该线程应该监视自启动以来经过的时间,如果时间超过某个阈值,它将杀死最初启动它的线程。为了通知这个新线程,要杀死哪个线程,新线程的对象被传递给要监视的线程的对象。

简而言之,这就是:

A创建B,B创建C,B告诉C关于自身,C保留时间,如果时间到期C杀死B(我在B的run方法中使用“currentThread()”将细节传递给C并且我已经确认确实传递了正确的对象)

现在,问题在于,由于某种原因,调用B.interrupt()会导致C本身被杀死。

[注意:大写字母表示线程名称]

4 个答案:

答案 0 :(得分:2)

我认为您的代码出了问题(除非我没有正确使用您的规范)。下面的代码按预期运行(对于可怕的嵌套结构感到抱歉):

输出是:

C is about to interrupt B
B is interrupted
C is still alive... is B alive yet?false

代码是:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;


public class Scrap {
    public static void main(String[] args) {
        Thread A = new Thread() {
            @Override
            public void run() {
                Thread B = new Thread() {
                    @Override
                    public void run() {
                        final CountDownLatch latch = new CountDownLatch(1);
                        final AtomicReference<Thread> pointer = new AtomicReference<Thread>();
                        Thread C = new Thread() {
                            @Override
                            public void run() {
                                try {
                                    //wait for B to be ready
                                    latch.await();
                                    Thread.sleep(2000);
                                    System.out.println("C is about to interrupt B");
                                    pointer.get().interrupt();
                                    Thread.sleep(2000);
                                    System.out.println("C is still alive... is B alive yet? " + pointer.get().isAlive());

                                } catch (InterruptedException e) {
                                    System.out.println("C interrupted");
                                    return;
                                }
                            }
                        };//C
                        C.start();
                        latch.countDown();
                        //Not sure how you did it, so just going with this:
                        pointer.set(Thread.currentThread());


                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            System.out.println("B is interrupted");
                            return;
                        }
                        System.out.println("B survived");

                    }
                };//B
                B.start();
            }
        };
        A.start();
    }
}

我的(狂野)猜测是线程间可见性。在上面的代码中,我使用原子引用来确保可见性。如果你没有这样做,你传递线程B的引用(的值)的任何字段都可能对C不可见。然后当C试图中断这个Thread对象时,它看到null并且中断导致NullPointerExceptin ,不知怎的,你没有注意到它?

答案 1 :(得分:1)

检查SecurityException时是否收到B.interrupt()。此外,你确定你的B.interrupt()不会简单地返回并且线程C成功完成吗?基于javadocs,看起来线程C调用B.interrupt()将设置线程B的中断状态并完成运行。我不认为线程B会在你的情况下得到任何异常,除非它满足特殊要求(比如,等待监视器,等待InterruptibleChannel等)。

答案 2 :(得分:1)

另一种可能性是,C中断成功并返回,但B没有响应。这很有可能,因为如果相应地编码B,则中断仅起作用。

有两种方法可以对中断做出反应 1.检查中断标志(通常在需要很长时间的操作之前)

if(Thread.currentThread().isInterrupted()){
    log.info("Cancel requested");
    return;
}
someStuffThatTakesLongTimeToExecute();

2.关于中断异常的行为

catch(InterruptedException e){
    log.info("Cancel Requested");

    //Preserve interrupted status.
    //If this class is the owner of the thread,
    //Not necessary.
    Thread.currentThread().interrupt(); 

    return;
}

答案 3 :(得分:-1)

如果你问我,这实际上是正常行为。如果你打断B,它将被垃圾收集。由于对C的唯一引用也是GC'd,因此它将不再存在/运行。

最好的想法可能是确保有一个线程管理线程B和C(并将线程C注入线程B)。这样,总会有一个对线程C的引用,并且它可以杀死线程B.(但是你必须要小心你在管理线程中对线程B做了什么)