1.ThreadLocal介绍
Java实现多线程的2种方式,继承Thread类和实现Runnable接口。今天我们介绍下另外一种常用的多线程类ThreadLocal类。
ThreadLocal在维护变量时,为每个使用变量的线程提供了独立的副本,所以每个线程都可以独立的改变自己的副本,而不影响其他线程对应的副本。
2.原理
ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:
void set(Object value)设置当前线程的线程局部变量的值。
public Object get()该方法返回当前线程所对应的线程局部变量。
public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。
3.Thread和ThreadLocal实例对比
//Thread实例
package com.tngtech.thread;
/*
*
* @author tngtech
* @date 2015年12月29日
*<p>博客:http://blog.csdn.net/jacman
*<p>Github:https://github.com/tangthis
*
*/
public class ThreadDemo implements Runnable{
private Integer i = 1;
@Override
public void run() {
for(int j = 0 ; j < 10 ; j++){
i = i + j;
}
System.out.println("变量值为:" + i);
}
public static void main(String[] args) {
ThreadDemo threadDemoRunnable = new ThreadDemo();
Thread thread1 = new Thread(threadDemoRunnable);
Thread thread2 = new Thread(threadDemoRunnable);
thread1.start();
//为了看到更明显的效果,线程睡眠1s,再启动另外一个线程
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
thread2.start();
//打印结果
//变量值为:46
//变量值为:91
//变量在多个线程间是共享的
}
}
在ThreadDemo中,我们修改变量i的值,根据输出结果,发现i变量在多个线程间是共享的。下面看下ThreadLocal的实例:
/**
* ThreadLocal实例
*/
package com.tngtech.thread;
/*
* ThreadLocal实例
* @author tngtech
* @date 2015年12月29日
*<p>博客:http://blog.csdn.net/jacman
*<p>Github:https://github.com/tangthis
*
*/
public <