将 ThreadLocal 用于 JDBC 连接是一种好习惯吗?
Is it good practice to use ThreadLocal for JDBC Connections?
我不确定我是否了解 ThreadLocals。有时您会读到,一种常见的做法是将 JDBC 连接作为 ThreadLocals,以便每个线程都获得自己的连接副本。假设下面的套接字是一个 JDBC 连接。然后我做:
public ThreadLocalSocket() throws IOException {
Runnable runnable = new Runnable() {
ThreadLocal<Socket> threadLocal = new ThreadLocal<>();
@Override
public void run() {
try {
threadLocal.set(new Socket("www.google.com", 80));
} catch (IOException e) {e.printStackTrace();}
Thread thread = Thread.currentThread();
for (int j = 0; j < 10 ; j++) {
Socket sock = threadLocal.get();
if (thread.getName().equals("t1")) {
if (!sock.isClosed()) {
try {
sock.close();
} catch (IOException e) {e.printStackTrace();}
}
}
System.out.println("Thread: " + thread.getName()+ ", is closed? " + sock.isClosed() + ", sock hashCode = " + sock.hashCode());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();}
}
}
};
Thread t1 = new Thread(runnable);
t1.setName("t1");
Thread t2 = new Thread(runnable);
t2.setName("t2");
t1.start();
t2.start();
}
为什么我不能在没有 ThreadLocals 的情况下简单地做到这一点?以下代码片段中的行为与上面的代码示例完全相同:
public ThreadLocalSocket() throws IOException {
Runnable runnable = new Runnable() {
@Override
public void run() {
Socket socket = null;
try {
socket = new Socket("www.google.com", 80);
} catch (IOException e) {e.printStackTrace();}
Thread thread = Thread.currentThread();
for (int j = 0; j < 10 ; j++) {
if (thread.getName().equals("t1")) {
if (!socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {e.printStackTrace();}
}
}
System.out.println("Thread: " + thread.getName()+ ", is closed? " + socket.isClosed() + ", socket hashCode = " + socket.hashCode());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();}
}
}
};
Thread t1 = new Thread(runnable);
t1.setName("t1");
Thread t2 = new Thread(runnable);
t2.setName("t2");
t1.start();
t2.start();
}
是的,在您的用例中,它毫无用处。
ThreadLocal instances are typically private static fields in classes
that wish to associate state with a thread (e.g., a user ID or
Transaction ID).
典型的用例是将 ThreadLocal
作为一种全局成员,这样您就不必传递引用值。您通过一些 static
方法公开它,您编写的每一段代码都可以访问它,而不必每次都注入它。
例如,Spring MVC 提供了 class RequestContextHolder
,它保留对 ServletRequest
对象的 ThreadLocal
引用。由于 servlet 容器通常(即非异步模式)通过在单个线程中处理请求来工作,而不是必须将 ServletRequest
传递给处理流程中的每个组件,Spring 设置它一旦在 RequestContextHolder
中,其他组件就可以通过 static
辅助方法(实际上只是请求的属性)访问它。
我不确定我是否了解 ThreadLocals。有时您会读到,一种常见的做法是将 JDBC 连接作为 ThreadLocals,以便每个线程都获得自己的连接副本。假设下面的套接字是一个 JDBC 连接。然后我做:
public ThreadLocalSocket() throws IOException {
Runnable runnable = new Runnable() {
ThreadLocal<Socket> threadLocal = new ThreadLocal<>();
@Override
public void run() {
try {
threadLocal.set(new Socket("www.google.com", 80));
} catch (IOException e) {e.printStackTrace();}
Thread thread = Thread.currentThread();
for (int j = 0; j < 10 ; j++) {
Socket sock = threadLocal.get();
if (thread.getName().equals("t1")) {
if (!sock.isClosed()) {
try {
sock.close();
} catch (IOException e) {e.printStackTrace();}
}
}
System.out.println("Thread: " + thread.getName()+ ", is closed? " + sock.isClosed() + ", sock hashCode = " + sock.hashCode());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();}
}
}
};
Thread t1 = new Thread(runnable);
t1.setName("t1");
Thread t2 = new Thread(runnable);
t2.setName("t2");
t1.start();
t2.start();
}
为什么我不能在没有 ThreadLocals 的情况下简单地做到这一点?以下代码片段中的行为与上面的代码示例完全相同:
public ThreadLocalSocket() throws IOException {
Runnable runnable = new Runnable() {
@Override
public void run() {
Socket socket = null;
try {
socket = new Socket("www.google.com", 80);
} catch (IOException e) {e.printStackTrace();}
Thread thread = Thread.currentThread();
for (int j = 0; j < 10 ; j++) {
if (thread.getName().equals("t1")) {
if (!socket.isClosed()) {
try {
socket.close();
} catch (IOException e) {e.printStackTrace();}
}
}
System.out.println("Thread: " + thread.getName()+ ", is closed? " + socket.isClosed() + ", socket hashCode = " + socket.hashCode());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();}
}
}
};
Thread t1 = new Thread(runnable);
t1.setName("t1");
Thread t2 = new Thread(runnable);
t2.setName("t2");
t1.start();
t2.start();
}
是的,在您的用例中,它毫无用处。
ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
典型的用例是将 ThreadLocal
作为一种全局成员,这样您就不必传递引用值。您通过一些 static
方法公开它,您编写的每一段代码都可以访问它,而不必每次都注入它。
例如,Spring MVC 提供了 class RequestContextHolder
,它保留对 ServletRequest
对象的 ThreadLocal
引用。由于 servlet 容器通常(即非异步模式)通过在单个线程中处理请求来工作,而不是必须将 ServletRequest
传递给处理流程中的每个组件,Spring 设置它一旦在 RequestContextHolder
中,其他组件就可以通过 static
辅助方法(实际上只是请求的属性)访问它。