欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java ThreadLocal使用

程序员文章站 2022-06-28 17:41:53
它是java中的一个为每个线程单独保存数据的类,也就是线程间数据隔离。1.使用public static void main(String[] args) throws Exception {//定义一个ThreadLocalThreadLocal local = new ThreadLocal(); new Thread(new Runnable() {@Overridepublic void run() {//为当前线程设置一个值local.set("thread...

它是java中的一个为每个线程单独保存数据的类,也就是线程间数据隔离。

1.使用

	 public static void main(String[] args) throws Exception {
	 //定义一个ThreadLocal
	 ThreadLocal<String> local = new ThreadLocal<String>();
	  new Thread(new Runnable() {
		@Override
		public void run() {
			//为当前线程设置一个值
			local.set("thread1");
			try {
				//线程休眠为了等一下其它线程设置值
				TimeUnit.SECONDS.sleep(5);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//打印
			System.out.println("第1个线程值"+local.get());
		}
	}).start();
	 
	 new Thread(new Runnable() {
			@Override
			public void run() {
				local.set("thread2");
				try {
					TimeUnit.SECONDS.sleep(5);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("第2个线程值"+local.get());
			}
		}).start();
 }

结果:
Java ThreadLocal使用
说明每个线程取到了自己的数据。

2.原理

先看一看ThreadLocal的set方法:

   /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
    	//获取当前线程
        Thread t = Thread.currentThread();
        //获取ThreadLocalMap对象
        ThreadLocalMap map = getMap(t);
        if (map != null)
        	//设置值
            map.set(this, value);
        else
        	//创建ThreadLocalMap对象
            createMap(t, value);
    }

先看一下getMap(t);我们发现getMap(t);取得是当前线程的threadLocals属性也就是说变量实际是存在每个线程自己的属性中的。

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

然后我们看一下ThreadLocalMap是什么类。
他是一个ThreadLocal中的内部类类似Map,他里面也有一个重要的内部类` static class Entry extends WeakReference<ThreadLocal<?>>
注意它是一个弱引用
关于java中引用类型以后有时间再写。

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
            	//将键设置为弱引用
                super(k);
                value = v;
            }
        }

接下来看一下创建ThreadLocalMap对象 createMap(t, value);

    void createMap(Thread t, T firstValue) {
    	//这个this是当前ThreadLocal对象
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
         table = new Entry[INITIAL_CAPACITY];
         int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
         //重点是这里将当前ThreadLocal对象设置为弱引用了
         table[i] = new Entry(firstKey, firstValue);
         size = 1;
         setThreshold(INITIAL_CAPACITY);
     }

其实就是创建一个ThreadLocalMap将key,value存进去。
最后get方法就相对简单了

   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();
    }

就是从当前线程取出ThreadLocalMap再根据当前ThreadLocal对象取出值。

3.内存泄漏问题

ThreadLocalMap的key是当前ThreadLocal为一个弱引用,当我们不想使用ThreadLocal时将它设置为null了,也就是要被垃圾回收器回收了,但是此时我们的ThreadLocalMap生命周期和Thread的一样,它不会回收,这时候就出现了一个现象。那就是ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。
所以最好在不使用ThreadLocal时,调用一下remove()方法移除存储的值。

这是我总结的我对ThreadLocal的理解,有不对的地方大家可以讨论。

本文地址:https://blog.csdn.net/wste3567/article/details/113970590

相关标签: java