【问题标题】:Is it good practice to use ThreadLocal for JDBC Connections?将 ThreadLocal 用于 JDBC 连接是一种好习惯吗?
【发布时间】:2023-04-07 15:37:01
【问题描述】:

我不确定我是否得到了这个 abous 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 的情况下简单地做到这一点?以下代码 sn-p 中的行为与上面的代码示例完全相同:

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();
}

【问题讨论】:

    标签: java jdbc thread-local


    【解决方案1】:

    是的,在您的用例中,它非常没用。

    javadoc of ThreadLocal 状态

    ThreadLocal 实例通常是类中的私有静态字段 希望将状态与线程相关联(例如,用户 ID 或 交易 ID)。

    典型的用例是将ThreadLocal 作为一种全局成员,这样您就不必传递引用的值。您通过一些static 方法公开它,并且您编写的每一段代码都可以访问它,而不必每次都注入它。


    例如,Spring MVC 提供了 RequestContextHolder 类,它保留了对 ServletRequest 对象的 ThreadLocal 引用。由于 servlet 容器通常(即非异步模式)通过在单个线程中处理请求来工作,并且不必将 ServletRequest 传递给处理流程中的每个组件,因此 Spring 在 RequestContextHolder 中设置一次其他组件可以通过static 辅助方法访问它(实际上只是请求的属性)。

    【讨论】:

    • 我明白了。那么ThreadLocals只是让线程以线程安全的方式访问对象而不是将对象的引用值传递给需要它的线程并避免同步的一种更简单的方法?
    • @rox 就其自身而言,线程局部变量不会使任何线程安全。您仍然可以通过其他机制将包装的值泄漏给其他线程。您必须完全遵循线程本地模式才能获得线程安全。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2018-03-18
    • 2019-03-06
    • 2013-03-30
    • 2015-09-02
    相关资源
    最近更新 更多