我正在看一些具有以下习语的遗留代码:
Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (myMap) {
item = myMap.get(myKey);
}
Run Code Online (Sandbox Code Playgroud)
我从Intelli-J的代码检查得到的警告是:
Synchronization on local variable 'myMap'
Run Code Online (Sandbox Code Playgroud)
这是适当的同步吗?为什么?
Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (someGlobalInstance.getMap()) {
item = myMap.get(myKey);
}
Run Code Online (Sandbox Code Playgroud) 使用线程本地数据库连接时,线程存在时需要关闭连接.
这只能我可以覆盖调用线程的run()方法.即使这不是一个很好的解决方案,因为在退出时,我不知道该线程是否曾打开过连接.
问题实际上更为通用:如何强制线程在线程局部对象退出时调用某些终结方法.
我查看了java 1.5的源代码,发现线程本地映射设置为null,这最终会导致垃圾收集调用finalize(),但我不想指望垃圾收集器.
以下覆盖似乎是不可避免的,以确保关闭数据库连接:
@Override
public void remove() {
get().release();
super.remove();
}
Run Code Online (Sandbox Code Playgroud)
其中,release()关闭数据库连接(如果已打开).但我们不知道线程是否曾使用过本地线程.如果此线程从未调用过get(),那么这里的工作就相当浪费:将调用ThreadLocal.initialValue(),在此线程上创建一个map等.
-
根据Thorbjørn的评论进一步澄清和举例:
java.lang.ThreadLocal是绑定到线程的对象的工厂类型.此类型具有对象的getter和工厂方法(通常由用户编写).当调用getter时,只有在此线程之前从未调用过它时才调用工厂方法.
使用ThreadLocal允许开发人员将资源绑定到线程,即使线程代码是由第三方编写的.
示例:假设我们有一个名为MyType的资源类型,我们希望每个线程只有一个.
在using类中定义:private static ThreadLocal resourceFactory = new ThreadLocal(){@ override protected MyType initialValue(){return new MyType(); }}
在此类的本地上下文中使用:public void someMethod(){MyType resource = resourceFactory.get(); resource.useResource(); }
get()只能在调用线程的生命周期中调用initialValue()一次.此时,MyType的实例将被实例化并绑定到此线程.此线程对get()的后续调用再次引用此对象.
经典用法示例是MyType是一些线程不安全的text/date/xml格式化程序.
但是这样的格式化程序通常不需要被释放或关闭,数据库连接也是如此,我使用java.lang.ThreadLocal来为每个线程建立一个数据库连接.
我看待它的方式,java.lang.ThreadLocal几乎是完美的.几乎是因为如果调用线程属于第三方应用程序,则无法保证资源的关闭.
我需要你的大脑绅士:通过扩展java.lang.ThreadLocal,我设法为每个线程绑定一个数据库连接,因为它的独占用途 - 包括我无法修改或覆盖的线程.我设法确保在线程因未捕获的异常而死的情况下关闭连接.
在正常线程退出的情况下,垃圾收集器关闭连接(因为MyType会覆盖finalize()).实际上它很快发生,但这并不理想. …
如果我的Web应用程序和ejb应用程序位于同一台机器上(在同一个JVM上)并且所有ejb调用都是本地调用,那么ThreadLocal在将信息从Web传递到ejb时是否会使用创建任何问题?
如果ejb调用是远程的,任何解决方法?将ThreadLocal信息可以从Web应用程序到EJB应用程序?ThreadLocal在这种情况下使用是否合适?
我正在研究和试验我的Java Web应用程序中的ThreadLocal变量.我使用ThreadLocal变量在请求之前存储用户名(从会话中收集),然后在请求后删除它.我通过在ServletFilter中调用静态实用程序方法来完成此操作.我不是简单地从会话中检索用户名的原因是因为我继承了一个系统,该系统具有长时间运行的进程,有时需要比会话超时允许的运行时间更长.我的想法是在处理请求之前获取用户名并将其存储在ThreadLocal变量中,这样我就可以在整个请求期间访问用户名,即使它花费的时间超过15分钟.
我的问题是:
这种设计是否存在任何安全/性能问题?如果有,那么什么是更好的解决方案?即使没有任何安全和/或性能问题,也欢迎更好的想法.我的解决方案中的代码段如下所示:
这是我的实用程序类,将在我的过滤器和我需要用户名的任何地方调用.
public abstract class UserUtil {
private static final ThreadLocal<String> threadUser = new ThreadLocal<String>();
public static String getUserId(){
return threadUser.get();
}
public static void setUserId(String userId){
threadUser.set(userId);
}
public static void removeUserId(){
threadUser.remove();
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的servlet过滤器,用于在请求之前设置用户名(并在请求后通过finally块清除它).
public class UserFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
HttpServletRequest request = (HttpServletRequest) servletRequest;
UserBean userBean …Run Code Online (Sandbox Code Playgroud) ThreadLocal执行期间存储在存储中的内容是否会在线程返回ThreadPool时自动清除(如预期的那样)?
在我的应用程序中,我ThreadLocal在一些执行期间放入一些数据,但如果下次使用相同的Thread,那么我在ThreadLocal存储中找到过时的数据.
我正在使用一个使用用户级上下文切换的运行时库(使用Boost :: Context),并且在使用thread_level变量时遇到了麻烦.考虑以下(简化)代码:
thread_local int* volatile tli;
int main()
{
tli = new int(1); // part 1, done by thread 1
UserLevelContextSwitch();
int li = *tli; // part 2, done by thread 2
cout << li;
}
Run Code Online (Sandbox Code Playgroud)
由于对thread_local变量有两次访问,因此编译器将main函数转换为沿着这些行的某些东西(与汇编相反):
register int** ptli = &tli; // cache address of thread_local variable
*ptli = new int(1);
UserLevelContextSwitch();
int li = **ptli;
cout << li;
Run Code Online (Sandbox Code Playgroud)
这似乎是一种合法的优化,因为volatile 的值tli不会缓存在寄存器中.但是, volatile 的地址tli实际上是缓存的,而不是从第2部分的内存中读取的.
这就是问题:在用户级上下文切换之后,执行第1部分的线程会转到其他位置.然后,第2部分由其他线程获取,该线程获得先前的堆栈和寄存器状态.但是现在正在执行第2部分的线程读取tli属于线程1的值.
我试图找出一种方法来阻止编译器缓存线程局部变量的地址,并且 …
我正在做一个广泛使用线程局部变量的库.你能指出一些基准测试来测试在C++中获取线程局部变量的不同方法的性能:
C++ 0x thread_local在提供它的编译器上执行得更好吗?
When the application is shutting down Valgrind reports these 3 issues:
==70== Mismatched free() / delete / delete []
==70== at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70== by 0x4870C89: check_free (dlerror.c:202)
==70== by 0x4870C89: check_free (dlerror.c:186)
==70== by 0x4870C89: free_key_mem (dlerror.c:221)
==70== by 0x4870C89: __dlerror_main_freeres (dlerror.c:239)
==70== by 0x4B59711: __libc_freeres (in /usr/lib/x86_64-linux-gnu/libc-2.29.so)
==70== by 0x482E19E: _vgnU_freeres (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so)
==70== by 0x4A0A3A9: __run_exit_handlers (exit.c:132)
==70== by 0x4A0A3D9: exit (exit.c:139)
==70== by …Run Code Online (Sandbox Code Playgroud) 为了更好地理解这个问题,代码如下:
// code 1
#include <iostream>
#include <thread>
struct tls_test {
tls_test()
{ std::cout << "tls_test ctor\n"; }
~tls_test()
{ std::cout << "tls_test dtor\n"; }
void print() const
{ std::cout << "tls_test print\n"; }
};
thread_local tls_test t;
void thread_1()
{
std::cout << "thread_1 started\n";
t.print();
std::cout << "thread_1 return\n";
}
int main()
{
std::thread trd{ thread_1 };
trd.join();
std::cout << "main return\n";
}
Run Code Online (Sandbox Code Playgroud)
我正在使用 TDM-GCC 和 Windows 10 来测试该程序。这是输出:
// code 1
#include <iostream>
#include <thread>
struct tls_test { …Run Code Online (Sandbox Code Playgroud) 可能重复:
gcc中的C++ 11 thread_local - 替代方法
有没有办法使用GCC的__thread完全模拟thread_local?
我想使用c ++ 11 thread_local来创建和使用thread_local变量,但由于gcc尚不支持,我使用的是gcc特有的__thread.我声明变量的方式是
myClass
{
public:
static __thread int64_t m_minInt;
};
__thread int64_t myClass::m_minInt = 100;
Run Code Online (Sandbox Code Playgroud)
当我编译它时,我得到一个错误
error: ‘myClass::minInt’ is thread-local and so cannot be dynamically initialized
Run Code Online (Sandbox Code Playgroud)
如何正确地做到这一点?
PS:gcc版本:4.6.3
thread-local ×10
c++ ×5
java ×5
boost ×2
boost-thread ×1
c++11 ×1
c++17 ×1
ejb ×1
gcc ×1
java-ee ×1
pthreads ×1
session ×1
stdthread ×1
synchronized ×1
threadpool ×1
volatile ×1