Thread(threadlocal)

一、簡介html

JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal爲解決多線程程序的併發問題提供了一種新的思路。使用這個工具類能夠很簡潔地編寫出優美的多線程程序,ThreadLocal並非一個Thread,而是Thread的局部變量。ThreadLocal用於保存某個線程共享變量:對於同一個static ThreadLocal,不一樣線程只能從中get,set,remove本身的變量,而不會影響其餘線程的變量。java

二、方法緩存

ThreadLocal.get: 獲取ThreadLocal中當前線程共享變量的值。多線程

ThreadLocal.set: 設置ThreadLocal中當前線程共享變量的值。併發

ThreadLocal.remove: 移除ThreadLocal中當前線程共享變量的值。工具

ThreadLocal.initialValue: ThreadLocal沒有被當前線程賦值時或當前線程剛調用remove方法後調用get方法,返回此方法值。性能

三、示例碼this

package com.it.demo.base.collection;

public class ThreadLocalDemo {
    private static final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>(){
        protected Object initialValue()
        {
            System.out.println("調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值!");
            return null;
        }
    };
    public static void main(String[] args)
    {
        new Thread(new RunnableDemo("tang")).start();
        new Thread(new RunnableDemo2("song")).start();
        new Thread(new RunnableDemo("ming")).start();
        new Thread(new RunnableDemo2("qin")).start();
    }
    public static class RunnableDemo implements Runnable
    {
        private String flag;
        RunnableDemo(String flag)
        {
            this.flag = flag;
        }
        public void run()
        {
            for(int i = 0; i < 5; i++)
            {
                // ThreadLocal.get方法獲取線程變量
                if(null == ThreadLocalDemo.threadLocal.get())
                {
                    // ThreadLocal.et方法設置線程變量
                    ThreadLocalDemo.threadLocal.set(0);
                    System.out.println("線程" + flag + ": 0");
                }
                else
                {
                    int num = (Integer)ThreadLocalDemo.threadLocal.get();
                    ThreadLocalDemo.threadLocal.set(num + 1);
                    System.out.println("線程" + flag + ": " + ThreadLocalDemo.threadLocal.get());
                    if(i == 3)
                    {
                        ThreadLocalDemo.threadLocal.remove();
                    }
                }
                try
                {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }

    public static class RunnableDemo2 implements Runnable {
        private String flag;
        RunnableDemo2(String name) {
            this.flag = name;
        }
        public void run() {
            for (int i = 0; i < 5; i++) {
                if (null == ThreadLocalDemo.threadLocal.get()) {
                    ThreadLocalDemo.threadLocal.set("a");
                    System.out.println("線程" + flag + ": a");
                } else {
                    String str = (String) ThreadLocalDemo.threadLocal.get();
                    ThreadLocalDemo.threadLocal.set(str + "a");
                    System.out.println("線程" + flag + ": " + ThreadLocalDemo.threadLocal.get());
                }
                try {
                    Thread.sleep(800);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

四、原理線程

線程共享變量緩存以下:htm

Thread.ThreadLocalMap<ThreadLocalObject>;

一、Thread: 當前線程,能夠經過Thread.currentThread()獲取。

二、ThreadLocal:咱們的static ThreadLocal變量。

三、Object: 當前線程共享變量。

咱們調用ThreadLocal.get方法時,其實是從當前線程中獲取ThreadLocalMap<ThreadLocalObject>,而後根據當前ThreadLocal獲取當前線程共享變量Object。

ThreadLocal.set,ThreadLocal.remove其實是一樣的道理。

 

這種存儲結構的好處:

一、線程死去的時候,線程共享變量ThreadLocalMap則銷燬。

二、ThreadLocalMap<ThreadLocal,Object>鍵值對數量爲ThreadLocal的數量,通常來講ThreadLocal數量不多,相比在ThreadLocal中用Map<Thread, Object>鍵值對存儲線程共享變量(Thread數量通常來講比ThreadLocal數量多),性能提升不少。

 

關於ThreadLocalMap<ThreadLocalObject>弱引用問題:

當線程沒有結束,可是ThreadLocal已經被回收,則可能致使線程中存在ThreadLocalMap<nullObject>的鍵值對,形成內存泄露。(ThreadLocal被回收,ThreadLocal關聯的線程共享變量還存在)。

雖然ThreadLocal的get,set方法能夠清除ThreadLocalMap中key爲null的value,可是get,set方法在內存泄露後並不會必然調用,因此爲了防止此類狀況的出現,咱們有兩種手段。

一、使用完線程共享變量後,顯示調用ThreadLocalMap.remove方法清除線程共享變量;

二、JDK建議ThreadLocal定義爲private static,這樣ThreadLocal的弱引用問題則不存在了。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息