我想重写行为,以便ExecutorService调用自定义方法。当线程被释放时,我想清除所有ThreadLocal变量。不太熟悉api,或者可能已经存在一些东西。
不确定线程池在线程完成工作时是如何管理线程的,但我假设线程池不会销毁线程,因为如果线程池不销毁线程,那么根据ThreadLocal描述,这将是非常昂贵的:
Each thread holds an implicit reference to its copy of a thread-local
* variable as long as the thread is alive and the {@code ThreadLocal}
* instance is accessible; after a thread goes away, all of its copies of
* thread-local instances are subject to garbage collection (unless other
* references to these copies exist).我需要清除ThreadLocal
发布于 2018-05-17 12:16:20
对于一个ExecutorService,你可以做一个自我清洁的任务。
public CleanerTask implements Runnable {
private Disposable realRunnable;
public CleanerTask(Disposable d) {
realRunnable = d;
}
public void run() {
realRunnable.run();
realRunnable.dispose();
}
}在本例中,Disposable是一个扩展Runnable的接口,并提供了一个清除ThreadLocal变量的dispose()方法。实现保证run()和dispose()在同一个线程中运行,因此可以安全地清除变量。
然后,在将任务提交给执行者之前,只需确保将任务包装在CleanerTask中即可。
但是,,,如果您没有绑定到ExecutorService,您可以扩展ThreadPoolExecutor,它提供了一个afterExecute方法。然后您只需在那里调用dispose() (在检查Runnable的类型是否正确之后)。
(我最初以为afterExecute没有在运行任务的线程中运行,但幸运的是,我想错了。)
发布于 2018-05-17 12:27:13
不确定您是否以正确的方式考虑线程和线程池。线程是用start()启动的,当它们的执行完成后,它们就被销毁了。线程的创建方式和时间取决于您的executor服务实现.您可能有一个只有在当前线程中运行任务。的执行器服务。池执行器服务可能使用无限循环启动其线程,等待提交的任务.然而,即使线程池通常也是灵活的,因为池只保留了有限数量的等待线程,如果有更多的线程,它就会让它们死掉(打破无限睡眠循环)。通常,如果执行抛出异常,线程也会被丢弃。
让线程-局部变量在一次执行中存活并不是一种好做法。每次执行之后,你都应该清理你的线程--本地人。不要等待线程的处理/销毁。
TL;博士并不试图黑入“线程破坏”,而是使用try/finally开始每一次执行,以设置和清理线程局部变量。
发布于 2018-05-17 14:07:02
线程将被实现线程池的executorservice重用,除非删除,否则这些线程本地条目将保留在线程跨任务的位置。如果您知道当一个任务完成时,它的线程本地值现在是不相关的,那么您可以清除它的就像Kayaman说的。
但是,线程局部变量的要点是,它们可以跨不同的组件使用,用于不同组件无法管理其作用域的情况。例如,web应用程序可以在带HTTP请求的过程中在过滤器中的线程本地中放置一些东西,使web控制器和服务可以在请求过程中使用,并在返回时清理过滤器中的线程本地。因此,在本例中,线程本地值的范围由过滤器管理,以便对参与该线程请求的所有对象可用,其中在“正常”(意味着不像Play这样的异步非阻塞设置) web应用程序中,请求由应用服务器中的一个线程处理。
如果确定不再需要ThreadLocal值的作用域对您来说如此简单,任务就可以清理它,那么您的代码听起来就像在不必要地使用ThreadLocals。我建议删除这些ThreadLocals并在任务中使用局部变量。不应将ThreadLocal用作参数传递的简单替代方法。
https://stackoverflow.com/questions/50390814
复制相似问题