ThreadLocal实践
這段時(shí)間在重構(gòu)項(xiàng)目的代碼,把項(xiàng)目主體的實(shí)現(xiàn)方式做了調(diào)整,ThreadLocal在其中扮演了非常重要的角色。
需求(使用場景):客戶端有一個(gè)請求過來,Java程序根據(jù)請求報(bào)文的參數(shù)決定調(diào)用某個(gè)服務(wù)提供數(shù)據(jù)。相信大家都會(huì)有類似的需求,拿我們業(yè)務(wù)來說,請求報(bào)文如下:
{"appid": "88888888","userid": 80,"datatype": "***","data":"{\"dataids\":[146,147,148]}" }一個(gè)用戶請求過來,需要根據(jù)datatype字段決定調(diào)不同的服務(wù)。
網(wǎng)上真的很多亂七八糟文章,講ThreadLocal中的ThreadLocalMap存放的key是線程對象,value是設(shè)置的線程局部變量,覺得挺有道理的,正好實(shí)現(xiàn)了線程數(shù)據(jù)隔離。但是仔細(xì)看源碼。發(fā)現(xiàn)每個(gè)Thread對象都維護(hù)了一個(gè)私有的ThreadLocalMap對象,ThreadLocalMap對象key是ThreadLocal對象,value是設(shè)置的變量值。這就有點(diǎn)扯了,看下面的示例代碼,反正這樣設(shè)計(jì)我是看不出來有什么好處,因?yàn)槊總€(gè)線程中會(huì)放置N個(gè)變量,那我就new N個(gè)ThreadLocal對象,Thread中的ThreadLocalMap維護(hù)的map key存放ThreadLocal對象,value放置值。
public class ThreadLocal<T> {public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t); //拿到線程私有的ThreadLocalMapif (map != null)map.set(this, value); //Thread對象中 map key是ThreadLocal對象 elsecreateMap(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();}void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue); }ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); //hashcode & 運(yùn)算去除高位table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);} }所以看到源碼之后,那些講ThreadLocal銷毀之后,Thread -> ThreadLoalMap -> Entry[ WeakRefrence, Object]? 因?yàn)榫€程還在,線程維護(hù)的Map的Entry數(shù)組也還存在,那數(shù)組中Entry的key是ThreadLocal的弱引用,value是值。所以會(huì)有內(nèi)容泄漏的風(fēng)險(xiǎn),所以最好是在使用完之后手動(dòng)調(diào)用remove()函數(shù)。
至于源碼中那些涉及Map在數(shù)組位置的求值,rehash我覺得都差不多,因?yàn)?6的初始大小我認(rèn)為是夠的,因?yàn)楹苌贂?huì)使用創(chuàng)建16個(gè)ThreadLocal對象。
public static void main(String[] args) {ThreadLocal<Person> threadLocal = new ThreadLocal<>(); //每個(gè)線程局部變量都需要?jiǎng)?chuàng)建一個(gè)ThreadLocal對象ThreadLocal<String> threadLocal2 = new ThreadLocal<>();AtomicInteger atomicInteger = new AtomicInteger(1000);ExecutorService executorService = Executors.newCachedThreadPool();//for(int i 0->10)executorService.submit(() -> {Person person = new Person();person.setIdcard(atomicInteger.getAndIncrement());person.setName(Thread.currentThread().getName());threadLocal.set(person);threadLocal2.set("haha");System.out.println(threadLocal.get());System.out.println(threadLocal2.get());System.out.println();threadLocal.remove();});executorService.shutdown();}
?
轉(zhuǎn)載于:https://www.cnblogs.com/zhengwangzw/p/9669194.html
總結(jié)
以上是生活随笔為你收集整理的ThreadLocal实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从路由原理出发,深入阅读理解react-
- 下一篇: CSS文本加省略号