Java ThreadLocal的用法解析

简介

java中常常使用ThreadLocal做为处理高并发访问的可选手段,ThreadLocal并非一个线程,而是”以线程为做用域“的一种面向对象的数据结构。其用法的也有着让人难以理解的怪异性。java

代码实战

定义一个线程类,其中定义了一个ThreadLocal<Integer> 的对象数据结构

 class AutoIntegerThread extends Thread
{
	//静态局部变量(注意java中的静态变量的生命周期,共享性,惟一性)
       private static ThreadLocal<Integer> autoInteger = new ThreadLocal<Integer>();
	//自增次数
	private int runTimes;
	
	public AutoIntegerThread(int runTimes) 
	{
		this.runTimes = runTimes;
	}

	@Override
	public void run() 
	{
		//为了说明ThreadLocal以线程为做用域,这里不适用同步代码块
		if(autoInteger.get()==null)
		{
			autoInteger.set(new Integer(0));
		}
		for (int i = 0; i < runTimes; i++) 
		{
		       autoInteger.set(autoInteger.get()+1);
			//这里使用如下,保证完整打印一下
			synchronized (autoInteger)
			{
				System.out.println(getName()+"==>"+autoInteger.get().intValue());
			}
		}
		
	} 
	
	public  Integer getFinalInteger() 
	{
		return autoInteger.get();
	}
}

测试代码并发

public class TestThreadLocal {	
  public static void main(String[] args) 
  {		
         AutoIntegerThread ait_1 = new AutoIntegerThread(5);		
         AutoIntegerThread ait_2 = new AutoIntegerThread(3);		
         AutoIntegerThread ait_3 = new AutoIntegerThread(3);

         ait_1.setName("ait_1");		
         ait_2.setName("ait_3");
         ait_3.setName("ait_2");		
         ait_1.start();		
         ait_2.start();		
         ait_3.start();
   }
}

打印结果ide

ait_1==>1
ait_2==>1
ait_2==>2
ait_2==>3
ait_1==>2
ait_3==>1
ait_1==>3
ait_3==>2
ait_1==>4
ait_3==>3
ait_1==>5

 

有上面的代码和代码注释可知,符合java中的静态变量的描述,【静态变量的生命周期和应用程序的生命周期彻底相同。静态变量具备共享性,惟一性,也就是说是单例】高并发

是的,静态变量能够说是一个完整的单例,但由打印结果可知,彷佛状况却违反了这种逻辑。测试

首先仔细想一想,单例的好处是下降了内存的使用,从而提升程序的执行效率(这里不可过度理解,其实,当静态变量太多时反而也会影响内存的回收,由于他的生命周期决定了他和程序时“同寿的”,静态变量尽可能少用的好,万事讲究一个“度”),另外单例的惟一性说明了他很是适合作“同步锁”。this

其次,从结果来看,貌似谁也没影响谁。有人质疑是否是 private 的问题,建议java基础不熟练的话就不要问这样的问题了,由于private只决定访问权限,而不决定变量的建立。所以也就说明了,以线程为做用域。spa

 

if(autoInteger.get()==null)
{
   autoInteger.set(new Integer(0));
}

 

从这段代码来看,若是是List集合来讲,只会运行一次,但程序彷佛并无这么作,而是分别在每一个线程个执行了一次。线程

看看源代码code

java.lang.ThreadLocal<T>

 

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

 

很显然,这个域做为map的key而存在,也就是说以“线程域”来建立和读取数据

而这个map的是属于Thread,看下面的源码

 ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

 

 

然而,进一步证实了threadlocal使用线程域

java.lang.Thread

ThreadLocal.ThreadLocalMap threadLocals = null;

 

 static class ThreadLocalMap {....}

反正是个map,版面估计不足,不粘了,你们能够去看看。

总结:ThreadLocal经过“线程域”能够实现做用域的区分,并使得程序更加高效

相关文章
相关标签/搜索