Java 线程监视器中的任何点是否重新启动死线程?

Java 线程监视器中的任何点是否重新启动死线程?,java,multithreading,Java,Multithreading,遇到以下代码(修改以明确我的观点): class ThreadWithQueue扩展线程{ 队列msgQueue; public void run(){while(!isInterrupted()){processMessage(queue.take());} } 类消息调度器{ ThreadsWithQueue[]线程; ... 无效调度消息(Msg){ int index=findMatchingThread(msg); 如果

遇到以下代码(修改以明确我的观点):

class ThreadWithQueue扩展线程{
队列msgQueue;
public void run(){while(!isInterrupted()){processMessage(queue.take());}
}             
类消息调度器{
ThreadsWithQueue[]线程;
...                    
无效调度消息(Msg){
int index=findMatchingThread(msg);
如果(!threads[index].isAlive()| | threads[index].isInterrupted()){
试一试{
threadCreateLock.lock();
threads[index]=createAndStartThread();
}最后{
threadCreateLock.unlock();
}
}
线程[index].queue.add(msg);
}
也就是说,有一个“消息调度器”,如果发现当前线程已死亡或中断,它可以重新启动(即创建一个新的)线程

请注意,这两个类都是由同一作者编写的,并且驻留在同一个包中

我的问题:
从设计/最佳实践的角度来看,“重新启动死线程”功能有什么意义吗?
在每个线程的run()方法(即在“ThreadWithQueue.run(){…}”内)中只使用“catch(Throwable){/*ignore/}*”不是更好的方法吗

“重新启动死线程”功能有什么意义吗 从设计/最佳实践的角度来看

请注意,如果旧线程死机或中断,您提供的代码将启动一个新线程。尽管这可能是由线程的
run()
引发意外异常引起的,但如果该线程被中断,特定线程也会自然死机。后一种行为是关闭系统的典型方式

在我看来,排队代码非常自然。当消息呈现给它时,它确保选择处理它的线程在实际发送消息之前既没有死也不会死

这不是更好的选择吗 一种方法,就是在每一个内部都有
catch(Throwable){/*ignore*/}
线程的
run()

不完全是。首先,对于所有类型的可丢弃的
来说,全面捕获并忽略策略是一个完全不好的主意。更具体地说,您的建议将阻止未捕获的异常处理程序处理此类异常。第二,如上所述,未捕获的异常不是唯一可能会导致其中一个线程死亡,因此您的建议不会免除消息调度器必须测试活动性并在发现需要时启动新线程的任务

“重新启动死线程”功能有什么意义吗 从设计/最佳实践的角度来看

请注意,如果旧线程死机或中断,您提供的代码将启动一个新线程。尽管这可能是由线程的
run()
引发意外异常引起的,但如果该线程被中断,特定线程也会自然死机。后一种行为是关闭系统的典型方式

在我看来,排队代码非常自然。当消息呈现给它时,它确保选择处理它的线程在实际发送消息之前既没有死也不会死

不是更好吗 一种方法,就是在每一个内部都有
catch(Throwable){/*ignore*/}
线程的
run()


不完全是。首先,对于所有类型的可丢弃的
来说,全面捕获并忽略策略是一个完全不好的主意。更具体地说,您的建议将阻止未捕获的异常处理程序处理此类异常。第二,如上所述,未捕获的异常不是唯一可能会导致其中一个线程死亡,因此您的建议不会免除消息调度程序在需要时必须测试活动性和启动新线程的任务。

通常,当您不知道处理是否正常时,可以重新启动线程,而不是在捕获并报告异常后继续de在异常情况下已正确清理。最值得注意的是,只要线程处于活动状态,就可能存在具有关联值的
ThreadLocal
变量

尽管如此,这里还是有一些奇怪的事情
作为重新启动的标准没有多大意义,因为前面的测试已经证明线程仍然处于活动状态。因此,可能是这样的,在
processMessage
中的某个位置,中断将被使用和处理,并在返回主循环时被重置。因此,最后,您将有两个正在运行的线程其中e个将永远挂在
队列中。一旦队列为空,请使用()
。您可能可以在
processMessage
的当前代码中排除这种情况,但是,您最好停止任何代码开发,以确保将来不会激活定时炸弹

此外,这里还有几个可能的争用条件。线程可能在
isAlive()
isInterrupted()之后立即死亡
已被选中,因此您仍在排队等待一个死线程。但由于无论如何都没有尝试将死线程的挂起消息传输到新线程,因此当线程因异常而死亡时,任意数量的消息可能会丢失。即使在
dispatchMessage()中有这样的传输
,这意味着线程死亡后,在新线程开始处理悬空队列之前,直到尝试将新消息调度到同一线程为止。显然,生成新线程应该是
class ThreadWithQueue extends Thread {
        Queue<Msg> msgQueue;
        public void run() { while (!isInterrupted()) {processMessage(queue.take());}
}             

class MessageDispatcher {
    ThreadsWithQueue[] threads;
    ...                    
    void dispatchMessage(Msg msg) {
        int index = findMatchingThread(msg);
        if (!threads[index].isAlive() || threads[index].isInterrupted()){
            try {
                threadCreateLock.lock();
                threads[index] = createAndStartThread();
            } finally {
                threadCreateLock.unlock();
            }
        }
        threads[index].queue.add(msg);
    }