通常我们创建的变量可以被任一个线程访问并修改,如果想实现每一个线程都有自己专属本地变量时,该变量不受其他线程影响,此时可以使用ThreadLocal。
ThreadLocal有三个常用方法,set()、get()、remove()。ThreadLocal<Integer> local = new ThreadLocal<>();
调用local.set()方法,对当前线程进行赋值。事实上set的值保存在当前线程的ThreadLocalMap中,而不是ThreadLocal中,ThreadLocal可以看作仅对ThreadLocalMap进行了封装,只传递参数,ThreadLocalMap可以看作是为ThreadLocal定制的HashMap。存放时,key就是ThreadLocal对象即这里定义的local,我们添加的变量Integer值作为value来存放。每个线程都有自己的ThreadLocalMap。
当我们在同一个线程中定义了第二个或多个ThreadLocal时,ThreadLocal<Integer> local2 = new ThreadLocal<>(); 接着通过local2.set()进行赋值时,值还会保存到仅有的一个ThreadLocalMap中,而不会再创建一个ThreadLocalMap。源码中是这样,两个ThreadLocal属于同一线程,就直接往map中添加元素,所以只存在一个ThreadLocalMap:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } local.get()、local2.get()分别获取到的是当前线程中我们存放的Integer变量值。使用线程池(顺便学一下线程池的使用哈哈)创建10个线程来存放Integer值 1-10。
public class ThreadLocalTest { public static void main(String[] args) throws InterruptedException{ ThreadLocal<Integer> local = new ThreadLocal<>(); //创建一个线程池,初始化10个线程,最多15个线程,60SECONDS,多出的线程经过60s没活就回收, // 保持10个线程,new LinkedBlockingQueue() 用来放任务的集合 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10,15, 60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>()); for (int i = 0; i < 10; i++) { int I = i + 1; //执行一次为一个线程,执行十次共10个线程 threadPool.execute(new Runnable() { @Override public void run() { local.set(I); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 的Integer值为:"+ local.get() ); } }); } threadPool.shutdown(); } }