ThreadLocal简介
ThreadLocal是Java中的线程局部变量,用于存放线程的局部变量。java
ThreadLocal为每一个线程的中并发访问的数据提供一个副本,经过访问副原本运行业务,这样的结果是耗费了内存,可是确避免线程同步所带来性能消耗,也减小了线程并发控制的复杂度。mysql
首先看一下ThreadLocal的API:sql
- get():返回此线程局部变量的当前线程副本中的值。
- protected T initialValue(): 返回此线程局部变量的当前线程的“初始值”。
- void remove(): 移除此线程局部变量当前线程的值。
- void set(T value): 将此线程局部变量的当前线程副本中的值设置为指定值。
能够看出ThreadLocal内部应该就是封装了一个Map,本身实现ThreadLocal:数据库
public class SimpleThreadLocal { private Map valueMap = Collections.synchronizedMap(new HashMap()); public void set(Object newValue) { //①键为线程对象,值为本线程的变量副本 valueMap.put(Thread.currentThread(), newValue); } public Object get() { Thread currentThread = Thread.currentThread(); //②返回本线程对应的变量 Object o = valueMap.get(currentThread); //③若是在Map中不存在,放到Map中保存起来 if (o == null && !valueMap.containsKey(currentThread)) { o = initialValue(); valueMap.put(currentThread, o); } return o; } public void remove() { valueMap.remove(Thread.currentThread()); } public Object initialValue() { return null; } }
以上代码很好理解,JDK中的实现比这复杂,能够自行查看源码。安全
ThreadLocal基本使用
ThreadLocal对象一般用于防止对可变的单实例变量或全局变量进行共享。服务器
当一个类中使用了static成员变量的时候,必定要多问问本身,这个static成员变量须要考虑线程安全吗?也就是说,多个线程须要独享本身的static成员变量吗?若是须要考虑,不妨使用ThreadLocal。多线程
例如,在单线程应用程序中可能会维护一个全局的数据库链接,并在程序启动的时候初始化这个链接,从而避免在调用每一个方法的时候都要传递一个Connection对象。因为JDBC的链接对象不必定时线程安全的,所以,当多线程应用程序在没有协同的状况下使用全局变量时,就是否是线程安全的。经过把JDBC的链接保存到ThreadLocal对象中,每一个线程都会拥有本身的链接。并发
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionManager { private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { @Override protected Connection initialValue() { Connection conn = null; try { conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "username", "password"); } catch (SQLException e) { e.printStackTrace(); } return conn; } }; public static Connection getConnection() { return connectionHolder.get(); } public static void setConnection(Connection conn) { connectionHolder.set(conn); } }
ThreadLocal须要注意的点
只要使用了“池”(线程池、链接池),在使用ThreadLocal时,尤为须要注意,每一个线程在使用ThreadLocal的时候,必须对ThreadLocal执行一次clear操做,避免出现线程污染问题。ide
线程池中的线程是重复利用的,只要线程还在,ThreadLocal线程本地变量会一直存在系统中,在JavaEE的服务器中尤其明显。性能