中断未知线程

时间:2017-08-24 10:02:59

标签: java multithreading

考虑以下(简化)类,旨在允许我的整个组件在完全停止之前进入某个临时状态。
(临时状态的目的是允许组件完成其现有任务,但拒绝任何新任务)。
可以从任意数量的线程多次启动和停止组件。

class StopHandler {
    boolean isStarted = false;

    synchronized void start() {isStarted = true;}

    //synchronized as I do want the client code to block until the component is stopped.
    //I might add some async method as well, but let's concentrate on the sync version only.
    synchronized void stop(boolean isUrgent) {
        if (isStarted) {
            if (!isUrgent) {
                setGlobalState(PREPARING_TO_STOP); //assume it is implemented
                try {Thread.sleep(10_000L);} catch (InterruptedException ignored) {}
            }
            isStarted = false;
    }
}

当前实现的问题是,如果某个客户端代码需要在处于临时状态时紧急停止该组件,它仍然需要等待。
例如:

//one thread
stopHandler.stop(false); //not urgent => it is sleeping
//another thread, after 1 millisecond:
stopHandler.stop(true); //it's urgent, "please stop now", but it will wait for 10 seconds

你会如何实现它?
我可能需要中断睡眠线程,但我没有睡眠线程对象可以调用' interrupt()'。

2 个答案:

答案 0 :(得分:1)

如何在调用sleep之前直接在StopHandler字段中存储对当前Thread的引用(由Thread.currentThread()返回)?这将允许您在后续紧急呼叫中中断它,以防线程仍处于活动状态。

答案 1 :(得分:0)

无法找到比Lars建议的解决方案更好的解决方案。 只需要封装睡眠管理以保证完整性。

class SleepHandler {
        private final ReentrantLock sleepingThreadLock;
        private volatile Thread sleepingThread;

        SleepHandler() {
            sleepingThreadLock = new ReentrantLock();
        }

        void sleep(long millis) throws InterruptedException {
            setSleepingThread(Thread.currentThread());
            Thread.sleep(millis);
            setSleepingThread(null);
        }

        void interruptIfSleeping() {
            doWithinSleepingThreadLock(() -> {
                if (sleepingThread != null) {
                    sleepingThread.interrupt();
                }
            });
        }

        private void setSleepingThread(@Nullable Thread sleepingThread) {
            doWithinSleepingThreadLock(() -> this.sleepingThread = sleepingThread);
        }

        private void doWithinSleepingThreadLock(Runnable runnable) {
            sleepingThreadLock.lock();
            try {
                runnable.run();
            } finally {
                sleepingThreadLock.unlock();
            }
        }
    }

使用这个助手类,处理原始问题是微不足道的:

void stop(boolean isUrgent) throws InterruptedException {
    if (isUrgent) {sleepHandler.interruptIfSleeping();} //harmless if not sleeping
    try {
        doStop(isUrgent); //all the stuff in the original 'stop(...)' method
    } catch (InteruptedException ignored) {
    } finally {
        Thread.interrupted(); //just in case, clearing the 'interrupt' flag as no need to propagate it futher
    }