Java 中断未知线程
考虑以下(简化的)类,该类旨在允许我的整个组件在完全停止之前进入某种临时状态Java 中断未知线程,java,multithreading,Java,Multithreading,考虑以下(简化的)类,该类旨在允许我的整个组件在完全停止之前进入某种临时状态(临时状态的目的是允许组件完成其现有任务,但拒绝任何新任务) 可以从任意数量的线程多次启动和停止组件 class StopHandler { boolean isStarted = false; synchronized void start() {isStarted = true;} //synchronized as I do want the client code to block u
(临时状态的目的是允许组件完成其现有任务,但拒绝任何新任务)
可以从任意数量的线程多次启动和停止组件
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()”的休眠线程对象。在调用sleep之前直接在StopHandler的字段中存储对当前线程(由thread.currentThread()返回)的引用如何?这将允许您在随后的紧急调用中中断它,以防线程仍然处于活动状态。找不到比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
}
为什么在这里使用同步方法?由于没有为
isStarted
变量获取参数,即使我调用它10次,我也知道最后的结果是什么isStarted=false
顺便说一句,您可能希望在睡眠后更改状态(睡眠后不是准备停止,而是停止),因为如果您从不同线程调用它10次,您希望它们一个接一个地发生。使用'isUrgent=false'应该需要100秒。如果您试图在它停止的过程中启动它,它也应该等待。因此,启动isStart
到false
需要100秒?然后您会遇到一个问题,因为第一个“none-urgent”调用将在10秒后更改该值,并且由于第一个条件为false,以下线程将不会执行任何操作。如果您只想在每次等待呼叫完成时更改值,则始终可以同步“none Emergency”块并管理等待队列。对不起,我的意思是开始()、停止(false)、开始()、停止(false)等10次。虽然通话几乎是同时进行的,但这应该需要大约100秒(可能更少)。这可能会起作用,但似乎有点“太手动”。我想可能有人会建议使用不同的java并发结构,比如闩锁等。无论如何,这是个好主意