在我的Java类中,我有时会ThreadLocal主要使用一种方法来避免不必要的对象创建:
@net.jcip.annotations.ThreadSafe
public class DateSensitiveThing {
private final Date then;
public DateSensitiveThing(Date then) {
this.then = then;
}
private static final ThreadLocal<Calendar> threadCal = new ThreadLocal<Calendar>() {
@Override
protected Calendar initialValue() {
return new GregorianCalendar();
}
};
public Date doCalc(int n) {
Calendar c = threadCal.get();
c.setTime(this.then):
// use n to mutate c
return c.getTime();
}
}
Run Code Online (Sandbox Code Playgroud)
我这样做是出于正当的原因 - GregorianCalendar是那些光荣的有状态,可变,非线程安全的对象之一,它提供跨多个调用的服务,而不是表示值.此外,它被认为是"昂贵的"实例化(这是否真实不是这个问题的重点).(总的来说,我真的很佩服它:-))
但是,如果我在任何聚集线程的环境中使用这样的类 - 并且我的应用程序无法控制这些线程的生命周期 - 那么就有可能发生内存泄漏.Servlet环境就是一个很好的例子.
事实上,当一个webapp停止时,Tomcat 7就像这样嘶嘶作响:
严重:Web应用程序[]创建了一个ThreadLocal,其键为[org.apache.xmlbeans.impl.store.CharUtil $ 1](值[org.apache.xmlbeans.impl.store.CharUtil$1@2aace7a7])和一个值类型为[java.lang.ref.SoftReference](值[java.lang.ref.SoftReference@3d9c9ad4]),但在Web应用程序停止时无法将其删除.线程将随着时间的推移而更新,以避免可能的内存泄漏.2012年12月13日下午12:54:30 org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
(在特定情况下,甚至我的代码都没有这样做).
这里给出的ThreadLocal的目的表明该变量是访问包含ThreadLocal变量的对象的任何Thread的本地变量.将ThreadLocal变量作为类的成员然后将其作为Thread的本地变量而不是将本地变量赋予Thread本身,它会有什么不同?
我使用ExecutorService和Future(这里是示例代码)在一个带有超时的单独线程中运行一个进程(线程"生成"发生在AOP方面).
现在,主线程是Resteasy请求.Resteasy使用一个或多个ThreadLocal变量来存储我需要在Rest方法调用中的某个时刻检索的一些上下文信息.问题是,由于Resteasy线程在新线程中运行,因此ThreadLocal变量将丢失.
将Resteasy使用的任何ThreadLocal变量"传播"到新线程的最佳方法是什么?似乎Resteasy使用多个ThreadLocal变量来跟踪上下文信息,我想"盲目地"将所有信息传递给新线程.
我查看了子类化ThreadPoolExecutor并使用beforeExecute方法将当前线程传递给池,但我找不到将ThreadLocal变量传递给池的方法.
有什么建议吗?
谢谢
据我所知,Servlet 3规范引入了异步处理功能.除此之外,这意味着可以并且将重用相同的线程来处理另一个并发的HTTP请求.这不是革命性的,至少对于之前与NIO合作的人来说至少是这样.
无论如何,这导致另一个重要的事情:没有ThreadLocal变量作为请求数据的临时存储.因为如果同一个线程突然成为另一个HTTP请求的运营商线程,请求本地数据将暴露给另一个请求.
所有这些都是基于阅读文章的纯粹推测,我没有时间玩任何Servlet 3实现(Tomcat 7,GlassFish 3.0.X等).
所以,问题:
ThreadLocal将不再是一个方便的黑客来保存请求数据?ThreadLocals来证明上述内容?编辑:别误会我的意思.我完全理解危险并ThreadLocal成为黑客.事实上,我总是建议不要在类似的环境中使用它.但是,不管你信不信,线程上下文的使用频率比你想象的要频繁得多.一个很好的例子是Spring的OpenSessionInViewFilter,根据它的Javadoc:
此过滤器通过当前线程使Hibernate会话可用,该线程将由事务管理器自动检测.
这不是严格的ThreadLocal(没有检查来源),但已经听起来令人震惊.我可以想到更多类似的场景,而且丰富的Web框架使得这种情况更有可能发生.
简而言之,许多人在这个黑客的基础上建造了他们的沙堡,无论是否有意识.因此,斯蒂芬的答案是可以理解的,但并不完全是我所追求的.我想得到一个确认是否有人真正尝试并能够重现失败的行为,所以这个问题可以作为被同一问题困扰的其他人的参考点.
每当我停止或重新部署webapp时,我都会看到很多类似的错误,
msg=The web application [] created a ThreadLocal with key of type [] (value []) and
a value of type [] (value []) but failed to remove it when the web application was
stopped. Threads are going to be renewed over time to try and avoid probable memory leak
Run Code Online (Sandbox Code Playgroud)
我不是在我的应用程序中创建任何ThreadLocals,而是引用可能正在创建这些ThreadLocals的许多库.我们目前正在使用Tomcat 7.我已经遇到过其他类似的问题[在Tomcat中重新部署应用程序时内存泄漏或catalina.out中的这些警告是什么?]但是所有这些只是暗示这是Tomcat功能警告你ThreadLocals没有被删除.我没有看到删除ThreadLocals的任何答案.我也看到一些关于线程没有停止的错误,
msg=The web application [] appears to have started a thread named [] but has
failed to stop it. This is very likely to create a …Run Code Online (Sandbox Code Playgroud) 我正在评论一个线程本地存储很好的答案,并回忆起关于异常的另一个信息性讨论
throw块中执行环境的唯一特殊之处在于rethrow引用了异常对象.
将两个和两个放在一起,不会在其主函数的函数catch块中执行整个线程,并将其与线程本地存储一起使用?
虽然很慢,但似乎工作正常.这是小说还是很有特色?还有另一种解决问题的方法吗?我最初的前提是否正确?get_thread您的平台会产生什么样的开销?优化的潜力是什么?
#include <iostream>
#include <pthread.h>
using namespace std;
struct thlocal {
string name;
thlocal( string const &n ) : name(n) {}
};
struct thread_exception_base {
thlocal &th;
thread_exception_base( thlocal &in_th ) : th( in_th ) {}
thread_exception_base( thread_exception_base const &in ) : th( in.th ) {}
};
thlocal &get_thread() throw() {
try {
throw;
} catch( thread_exception_base &local ) {
return local.th;
}
}
void print_thread() {
cerr << get_thread().name …Run Code Online (Sandbox Code Playgroud) 当你使用a ThreadLocal<T>和T实现IDisposable时,你应该如何处理ThreadLocal中的成员?
根据ILSpy,ThreadLocal的Dispose()和Dispose(bool)方法是
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
int currentInstanceIndex = this.m_currentInstanceIndex;
if (currentInstanceIndex > -1 && Interlocked.CompareExchange(ref this.m_currentInstanceIndex, -1, currentInstanceIndex) == currentInstanceIndex)
{
ThreadLocal<T>.s_availableIndices.Push(currentInstanceIndex);
}
this.m_holder = null;
}
Run Code Online (Sandbox Code Playgroud)
ThreadLocal似乎没有尝试在其子成员上调用Dispose.我不知道如何引用它内部分配的每个线程,所以我可以处理它.
我使用以下代码运行测试,该类从未处理过
static class Sandbox
{
static void Main()
{
ThreadLocal<TestClass> test = new ThreadLocal<TestClass>();
test.Value = new TestClass();
test.Dispose();
Console.Read();
}
}
class TestClass : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool Disposing)
{
Console.Write("I …Run Code Online (Sandbox Code Playgroud) 我知道Open Addressing和Chaining之间在解决哈希冲突方面的区别.在Java中HashSet,大多数基于哈希的基本数据结构HashMap主要使用链接技术.我读到ThreadLocal实际上使用了探测方案.所以我想理解为什么开放式寻址在Java中没有那么多用?我的意思是,使用该方案删除记录很困难,因为您必须使用一些特殊处理来标记这些单元格.然而,对于开放寻址方案,似乎存储器要求将是低的.
编辑:我只是想了解这个设计决定的可能主要原因/原因.我不想要更精细的细节.此外,我想知道为什么ThreadLocal使用较少见的开放寻址技术.我想这两个答案可以联系在一起.所以我更喜欢在同一个问题中提问.
我可能有一个Dog类,它有一个跨多个线程共享的实例.我计划将SLF4J用于所有日志记录:
public class Dog {
private Logger logger = LoggerFactory.getLogger(Dog.class);
// ...etc.
}
Run Code Online (Sandbox Code Playgroud)
我的logger实例线程安全吗?为什么/为什么不呢?
像这样.
struct some_struct
{
// Other fields
.....
__thread int tl;
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试这样做,但编译器给了我这个错误.
./cv.h:16:2: error: '__thread' is only allowed on variable declarations
__thread int tl;
Run Code Online (Sandbox Code Playgroud) thread-local ×10
java ×7
c++ ×2
threadpool ×2
.net-4.0 ×1
c ×1
c# ×1
concurrency ×1
exception ×1
hash ×1
idisposable ×1
logging ×1
resteasy ×1
servlet-3.0 ×1
servlets ×1
slf4j ×1
tomcat7 ×1