Java中的ThreadLocal

ThreadLocal其实,它就是一个容器,用于存放线程的局部变量。为每个线程保留一份变量副本。
我们来看下面的代码:
数据库连接工具

package com.xfl.concurrent;


import java.sql.Connection;
import java.sql.DriverManager;

/**
 * Created by XFL
 * time on 2017/5/16 23:43
 * description:
 */
public class DBUtil {
    // 数据库配置
    private static final String driver = "com.mysql.jdbc.Driver";
    private static final String url = "jdbc:mysql://localhost:3306/shop";
    private static final String username = "XFL";
    private static final String password = "********";
    // 定义一个数据库连接
    private static Connection conn = null;

    // 获取连接
    public static Connection getConnection() {
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    // 关闭连接
    public static void closeConnection() {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试线程

package com.xfl.concurrent;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created by XFL
 * time on 2017/5/16 23:50
 * description:
 */
public class ClientThread extends Thread {
    private int wait;
    private String threadName;

    public ClientThread(int wait, String threadName) {
        this.wait = wait;
        this.threadName = threadName;
    }

    @Override
    public void run() {
        Connection connection = DBUtil.getConnection();
        System.out.println("正在执行的线程: " + threadName);
        try {
            //模仿耗时操作任务
            Thread.sleep(wait);
        } catch (InterruptedException e) {
            System.out.println(e);
        }
        try {
            //主要是为了验证数据库连接是否关闭,可以起到模仿数据库操作的效果
            System.out.println("线程:" + threadName + " 的数据库连接是否关闭:" + connection.isClosed());
        } catch (SQLException e) {
            System.out.println(e);
        }
        DBUtil.closeConnection();
    }
}

测试代码

package com.xfl.concurrent;

/**
 * Created by XFL
 * time on 2017/5/16 23:34
 * description:ThreadLocal线程的局部变量
 * https://my.oschina.net/huangyong/blog/159489
 */
public class ThreadLocalTest {

    public static void main(String[] args) {
        //让线程1多等待一会,目的是为了让线程2和线程1拿到同一个数据库连接(同一个对象)
        Thread thread1 = new ClientThread(1500, "thread1");
        thread1.start();
        Thread thread2 = new ClientThread(500, "thread2");
        thread2.start();
    }
}

运行结果:
这里写图片描述
我们看到线程2会把线程1的数据库连接关闭,原因很简单因为线程1和线程2共用了一个数据库连接,因为我们在DBUtil中定义的Connection是static,修改方法有很多中比如将Connection定义在方法内部,每次都去new一个,当然关闭的方法也要做修改,最好的做法是使用ThreadLocal,为每个线程保留一份Connection的副本,不同的线程不共用一个连接,就不会出现上面的问题。
修改后的DBUtil

package com.xfl.concurrent;


import java.sql.Connection;
import java.sql.DriverManager;

/**
 * Created by XFL
 * time on 2017/5/16 23:43
 * description:
 */
public class DBUtil {
    // 数据库配置
    private static final String driver = "com.mysql.jdbc.Driver";
    private static final String url = "jdbc:mysql://localhost:3306/shop";
    private static final String username = "XFL";
    private static final String password = "********";
    // 定义一个数据库连接
    private static Connection conn = null;
    // 定义一个用于放置数据库连接的局部线程变量(使每个线程都拥有自己的连接)
    private static ThreadLocal<Connection> connContainer = new ThreadLocal<Connection>();
    // 获取连接
    public static Connection getConnection() {
        //从ThreadLocal中获取Connection
        Connection conn = connContainer.get();
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //将 connContainer放入到ThreadLocal中
            connContainer.set(conn);
        }
        return conn;
    }

    // 关闭连接
    public static void closeConnection() {
        //获取Connection
        Connection conn = connContainer.get();
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //移除Connection
            connContainer.remove();
        }
    }
}

运行结果:
这里写图片描述
我们可以看到线程1和线程2之间不会相互影响了。
参考资料:https://my.oschina.net/huangyong/blog/159725

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值