ThreadLocal的使用及实现

在java中,如果一个变量需要被多个线程访问,可以使用volatile来声明它为“易变的”。而假如一个变量要被持有它的某个线程独享,在java中,它可以使用java.lang.ThreadLocal类来实现线程本地存储的功能。这样,数据便只在同一个线程内可见和共享,因此,即便不同步也能保证线程之间不出现数据争用。

ThreadLocal使得各线程能够保持各自独立的一个对象,通过ThreadLocal.set()来设置对象的值,保存在每个线程自己都有的一个map对象当中,每个ThreadLocal对象会有一个线程范围内唯一hashcode作为key,ThreadLocal.get()内部通过这个key从map中取值,因此取出来的是各自自己线程中的对象,ThreadLocal实例事实上只是作为map的key来使用的。


一个ThreadLocal的例子:

 

Java代码    收藏代码
  1. package com.threadlocal.test;  
  2.   
  3. /** 
  4.  * @Author: chenkangxian 
  5.  * 
  6.  * @Annotation: 
  7.  * 
  8.  * @Date:2012-4-20 
  9.  *  
  10.  */  
  11. public class test {  
  12.   
  13.     class ConcurrentCount extends Thread{  
  14.           
  15.         ThreadLocal<Integer> count ;  
  16.           
  17.         public ConcurrentCount(ThreadLocal<Integer> count){  
  18.             this.count = count;  
  19.         }  
  20.   
  21.         @Override  
  22.         public void run() {  
  23.               
  24.             for(int i = 0; i < 10; i ++){  
  25.                   
  26.                 if(count.get() != null){  
  27.                     count.set(count.get() + 1);  
  28.                 }else{  
  29.                     count.set(0);  
  30.                 }  
  31.                   
  32.                 System.out.println("Thread: " + this.currentThread().getName() + ", count: " + count.get());  
  33.             }  
  34.               
  35.             return ;  
  36.         }  
  37.           
  38.     }  
  39.       
  40.     /** 
  41.      * Author: chenkangxian 
  42.      * 
  43.      * Last Modification Time: 2012-4-20 
  44.      * 
  45.      * @param args 
  46.      */  
  47.     public static void main(String[] args) {  
  48.   
  49.           
  50.         //所有线程均使用该变量,但是却不存在线程安全问题  
  51.         ThreadLocal<Integer> count = new ThreadLocal<Integer>();  
  52.           
  53.         test test = new test();  
  54.           
  55.         ConcurrentCount count1 = test.new ConcurrentCount(count);  
  56.         ConcurrentCount count2 = test.new ConcurrentCount(count);  
  57.         ConcurrentCount count3 = test.new ConcurrentCount(count);  
  58.         ConcurrentCount count4 = test.new ConcurrentCount(count);  
  59.           
  60.         count1.start();  
  61.         count2.start();  
  62.         count3.start();  
  63.         count4.start();  
  64.   
  65.     }  
  66.   
  67. }  

 

 

ThreadLocal使用归纳有两点:

1.每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。 
2.将一个共用的ThreadLocal实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象。

 

 

ThreadLocal实现的源代码:

 

Java代码    收藏代码
  1. /* 
  2.  * @(#)ThreadLocal.java 1.42 06/06/23 
  3.  * 
  4.  * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 
  5.  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 
  6.  */  
  7.   
  8. package java.lang;  
  9. import java.lang.ref.*;  
  10. import java.util.concurrent.atomic.AtomicInteger;  
  11.   
  12.        new ThreadLocal &lt; Integer > () { 

  13. public class ThreadLocal<T> {  
  14.  
  15.     private final int threadLocalHashCode = nextHashCode();  
  16.   
  17.     /** 
  18.      * The next hash code to be given out. Updated atomically. Starts at 
  19.      * zero. 
  20.      */  
  21.     private static AtomicInteger nextHashCode =   
  22.     new AtomicInteger();  
  23.   
  24.     /** 
  25.      * The difference between successively generated hash codes - turns 
  26.      * implicit sequential thread-local IDs into near-optimally spread 
  27.      * multiplicative hash values for power-of-two-sized tables. 
  28.      */  
  29.     private static final int HASH_INCREMENT = 0x61c88647;  
  30.   
  31.     /** 
  32.      * Returns the next hash code. 
  33.      */  
  34.     private static int nextHashCode() {  
  35.     return nextHashCode.getAndAdd(HASH_INCREMENT);   
  36.     }  
  37.   
  38.   
  39.      * @return the initial value for this thread-local 
  40.      */  
  41.     protected T initialValue() {  
  42.         return null;  
  43.     }  
  44.   
  45.     /** 
  46.      * Creates a thread local variable. 
  47.      */  
  48.     public ThreadLocal() {  
  49.     }  
  50.   
  51.    
  52.     public T get() {  
  53.         Thread t = Thread.currentThread();  
  54.         ThreadLocalMap map = getMap(t);  
  55.         if (map != null) {  
  56.             ThreadLocalMap.Entry e = map.getEntry(this);  
  57.             if (e != null)  
  58.                 return (T)e.value;  
  59.         }  
  60.         return setInitialValue();  
  61.     }  
  62.   

  63.     private T setInitialValue() {  
  64.         T value = initialValue();  
  65.         Thread t = Thread.currentThread();  
  66.         ThreadLocalMap map = getMap(t);  
  67.         if (map != null)  
  68.             map.set(this, value);  
  69.         else  
  70.             createMap(t, value);  
  71.         return value;  
  72.     }  

  73.     public void set(T value) {  
  74.         Thread t = Thread.currentThread();  
  75.         ThreadLocalMap map = getMap(t);  
  76.         if (map != null)  
  77.             map.set(this, value);  
  78.         else  
  79.             createMap(t, value);  
  80.     }  
  81.   

  82.      public void remove() {  
  83.          ThreadLocalMap m = getMap(Thread.currentThread());  
  84.          if (m != null)  
  85.              m.remove(this);  
  86.      }  
  87.   
  88.     /** 
  89.      * Get the map associated with a ThreadLocal. Overridden in 
  90.      * InheritableThreadLocal. 
  91.      * 
  92.      * @param  t the current thread 
  93.      * @return the map 
  94.      */  
  95.     ThreadLocalMap getMap(Thread t) {  
  96.         return t.threadLocals;  
  97.     }  
  98.   
  99.  
  100.     void createMap(Thread t, T firstValue) {  
  101.         t.threadLocals = new ThreadLocalMap(this, firstValue);  
  102.     }  
  103.   

  104.     static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {  
  105.         return new ThreadLocalMap(parentMap);  
  106.     }  
  107.   
  108.   
  109.     T childValue(T parentValue) {  
  110.         throw new UnsupportedOperationException();  
  111.     }  
  112.   
  113.  
  114.     static class ThreadLocalMap {  
  115.   
  116.      
  117.         static class Entry extends WeakReference<ThreadLocal> {  
  118.             /** The value associated with this ThreadLocal. */  
  119.             Object value;  
  120.   
  121.             Entry(ThreadLocal k, Object v) {  
  122.                 super(k);  
  123.                 value = v;  
  124.             }  
  125.         }  
  126.   
  127.         /** 
  128.          * The initial capacity -- MUST be a power of two. 
  129.          */  
  130.         private static final int INITIAL_CAPACITY = 16;  
  131.   
  132.         /** 
  133.          * The table, resized as necessary. 
  134.          * table.length MUST always be a power of two. 
  135.          */  
  136.         private Entry[] table;  
  137.   
  138.         /** 
  139.          * The number of entries in the table. 
  140.          */  
  141.         private int size = 0;  
  142.   
  143.         /** 
  144.          * The next size value at which to resize. 
  145.          */  
  146.         private int threshold; // Default to 0  
  147.   
  148.         /** 
  149.          * Set the resize threshold to maintain at worst a 2/3 load factor. 
  150.          */  
  151.         private void setThreshold(int len) {  
  152.             threshold = len * 2 / 3;  
  153.         }  
  154.   
  155.         /** 
  156.          * Increment i modulo len. 
  157.          */  
  158.         private static int nextIndex(int i, int len) {  
  159.             return ((i + 1 < len) ? i + 1 : 0);  
  160.         }  
  161.   
  162.         /** 
  163.          * Decrement i modulo len. 
  164.          */  
  165.         private static int prevIndex(int i, int len) {  
  166.             return ((i - 1 >= 0) ? i - 1 : len - 1);  
  167.         }  
  168.   
  169.         /** 
  170.          * Construct a new map initially containing (firstKey, firstValue). 
  171.          * ThreadLocalMaps are constructed lazily, so we only create 
  172.          * one when we have at least one entry to put in it. 
  173.          */  
  174.         ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {  
  175.             table = new Entry[INITIAL_CAPACITY];  
  176.             int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);  
  177.             table[i] = new Entry(firstKey, firstValue);  
  178.             size = 1;  
  179.             setThreshold(INITIAL_CAPACITY);  
  180.         }  
  181.   
  182.         /** 
  183.          * Construct a new map including all Inheritable ThreadLocals 
  184.          * from given parent map. Called only by createInheritedMap. 
  185.          * 
  186.          * @param parentMap the map associated with parent thread. 
  187.          */  
  188.         private ThreadLocalMap(ThreadLocalMap parentMap) {  
  189.             Entry[] parentTable = parentMap.table;  
  190.             int len = parentTable.length;  
  191.             setThreshold(len);  
  192.             table = new Entry[len];  
  193.   
  194.             for (int j = 0; j < len; j++) {  
  195.                 Entry e = parentTable[j];  
  196.                 if (e != null) {  
  197.                     ThreadLocal key = e.get();  
  198.                     if (key != null) {  
  199.                         Object value = key.childValue(e.value);  
  200.                         Entry c = new Entry(key, value);  
  201.                         int h = key.threadLocalHashCode & (len - 1);  
  202.                         while (table[h] != null)  
  203.                             h = nextIndex(h, len);  
  204.                         table[h] = c;  
  205.                         size++;  
  206.                     }  
  207.                 }  
  208.             }  
  209.         }  
  210.   
  211.     
  212.         private Entry getEntry(ThreadLocal key) {  
  213.             int i = key.threadLocalHashCode & (table.length - 1);  
  214.             Entry e = table[i];  
  215.             if (e != null && e.get() == key)  
  216.                 return e;  
  217.             else  
  218.                 return getEntryAfterMiss(key, i, e);  
  219.         }  
  220.   
  221.     
  222.         private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {  
  223.             Entry[] tab = table;  
  224.             int len = tab.length;  
  225.   
  226.             while (e != null) {  
  227.                 ThreadLocal k = e.get();  
  228.                 if (k == key)  
  229.                     return e;  
  230.                 if (k == null)  
  231.                     expungeStaleEntry(i);  
  232.                 else  
  233.                     i = nextIndex(i, len);  
  234.                 e = tab[i];  
  235.             }  
  236.             return null;  
  237.         }  
  238.   
  239.         /** 
  240.          * Set the value associated with key. 
  241.          * 
  242.          * @param key the thread local object 
  243.          * @param value the value to be set 
  244.          */  
  245.         private void set(ThreadLocal key, Object value) {  
  246.   
  247.             // We don't use a fast path as with get() because it is at  
  248.             // least as common to use set() to create new entries as  
  249.             // it is to replace existing ones, in which case, a fast  
  250.             // path would fail more often than not.  
  251.   
  252.             Entry[] tab = table;  
  253.             int len = tab.length;  
  254.             int i = key.threadLocalHashCode & (len-1);  
  255.   
  256.             for (Entry e = tab[i];  
  257.          e != null;  
  258.          e = tab[i = nextIndex(i, len)]) {  
  259.                 ThreadLocal k = e.get();  
  260.   
  261.                 if (k == key) {  
  262.                     e.value = value;  
  263.                     return;  
  264.                 }  
  265.   
  266.                 if (k == null) {  
  267.                     replaceStaleEntry(key, value, i);  
  268.                     return;  
  269.                 }  
  270.             }  
  271.   
  272.             tab[i] = new Entry(key, value);  
  273.             int sz = ++size;  
  274.             if (!cleanSomeSlots(i, sz) && sz >= threshold)  
  275.                 rehash();  
  276.         }  
  277.   
  278.         /** 
  279.          * Remove the entry for key. 
  280.          */  
  281.         private void remove(ThreadLocal key) {  
  282.             Entry[] tab = table;  
  283.             int len = tab.length;  
  284.             int i = key.threadLocalHashCode & (len-1);  
  285.             for (Entry e = tab[i];  
  286.          e != null;  
  287.          e = tab[i = nextIndex(i, len)]) {  
  288.                 if (e.get() == key) {  
  289.                     e.clear();  
  290.                     expungeStaleEntry(i);  
  291.                     return;  
  292.                 }  
  293.             }  
  294.         }  
  295.   
  296.    
  297.         private void replaceStaleEntry(ThreadLocal key, Object value,  
  298.                                        int staleSlot) {  
  299.             Entry[] tab = table;  
  300.             int len = tab.length;  
  301.             Entry e;  
  302.   
  303.        
  304.             int slotToExpunge = staleSlot;  
  305.             for (int i = prevIndex(staleSlot, len);  
  306.          (e = tab[i]) != null;  
  307.                  i = prevIndex(i, len))  
  308.                 if (e.get() == null)  
  309.                     slotToExpunge = i;  
  310.   
  311.             // Find either the key or trailing null slot of run, whichever  
  312.             // occurs first  
  313.             for (int i = nextIndex(staleSlot, len);  
  314.          (e = tab[i]) != null;  
  315.                  i = nextIndex(i, len)) {  
  316.                 ThreadLocal k = e.get();  
  317.   
  318.             
  319.                 if (k == key) {  
  320.                     e.value = value;  
  321.   
  322.                     tab[i] = tab[staleSlot];  
  323.                     tab[staleSlot] = e;  
  324.   
  325.                     // Start expunge at preceding stale entry if it exists  
  326.                     if (slotToExpunge == staleSlot)  
  327.                         slotToExpunge = i;  
  328.                     cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);  
  329.                     return;  
  330.                 }  
  331.   
  332.       
  333.                 if (k == null && slotToExpunge == staleSlot)  
  334.                     slotToExpunge = i;  
  335.             }  
  336.   
  337.             // If key not found, put new entry in stale slot  
  338.             tab[staleSlot].value = null;     
  339.             tab[staleSlot] = new Entry(key, value);  
  340.   
  341.             // If there are any other stale entries in run, expunge them  
  342.             if (slotToExpunge != staleSlot)  
  343.                 cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);  
  344.         }  
  345.   
  346.     
  347.         private int expungeStaleEntry(int staleSlot) {  
  348.             Entry[] tab = table;  
  349.             int len = tab.length;  
  350.   
  351.             // expunge entry at staleSlot  
  352.             tab[staleSlot].value = null;     
  353.             tab[staleSlot] = null;  
  354.             size--;  
  355.   
  356.             // Rehash until we encounter null  
  357.             Entry e;  
  358.             int i;  
  359.             for (i = nextIndex(staleSlot, len);  
  360.          (e = tab[i]) != null;  
  361.                  i = nextIndex(i, len)) {  
  362.                 ThreadLocal k = e.get();  
  363.                 if (k == null) {  
  364.                     e.value = null;  
  365.                     tab[i] = null;  
  366.                     size--;  
  367.                 } else {  
  368.                     int h = k.threadLocalHashCode & (len - 1);  
  369.                     if (h != i) {  
  370.                         tab[i] = null;  
  371.   
  372.                         // Unlike Knuth 6.4 Algorithm R, we must scan until  
  373.                         // null because multiple entries could have been stale.  
  374.                         while (tab[h] != null)  
  375.                             h = nextIndex(h, len);  
  376.                         tab[h] = e;  
  377.                     }  
  378.                 }  
  379.             }  
  380.             return i;  
  381.         }  
  382.   
  383.  
  384.         private boolean cleanSomeSlots(int i, int n) {  
  385.             boolean removed = false;  
  386.             Entry[] tab = table;  
  387.             int len = tab.length;  
  388.             do {  
  389.                 i = nextIndex(i, len);  
  390.                 Entry e = tab[i];  
  391.                 if (e != null && e.get() == null) {  
  392.                     n = len;  
  393.                     removed = true;  
  394.                     i = expungeStaleEntry(i);  
  395.                 }  
  396.             } while ( (n >>>= 1) != 0);  
  397.             return removed;  
  398.         }  
  399.   
  400.     
  401.         private void rehash() {  
  402.             expungeStaleEntries();  
  403.   
  404.             // Use lower threshold for doubling to avoid hysteresis  
  405.             if (size >= threshold - threshold / 4)  
  406.                 resize();  
  407.         }  
  408.   
  409.         /** 
  410.          * Double the capacity of the table. 
  411.          */  
  412.         private void resize() {  
  413.             Entry[] oldTab = table;  
  414.             int oldLen = oldTab.length;  
  415.             int newLen = oldLen * 2;  
  416.             Entry[] newTab = new Entry[newLen];  
  417.             int count = 0;  
  418.   
  419.             for (int j = 0; j < oldLen; ++j) {  
  420.                 Entry e = oldTab[j];  
  421.                 if (e != null) {  
  422.                     ThreadLocal k = e.get();  
  423.                     if (k == null) {  
  424.                         e.value = null// Help the GC  
  425.                     } else {  
  426.                         int h = k.threadLocalHashCode & (newLen - 1);  
  427.                         while (newTab[h] != null)  
  428.                             h = nextIndex(h, newLen);  
  429.                         newTab[h] = e;  
  430.                         count++;  
  431.                     }  
  432.                 }  
  433.             }  
  434.   
  435.             setThreshold(newLen);  
  436.             size = count;  
  437.             table = newTab;  
  438.         }  
  439.   
  440.         /** 
  441.          * Expunge all stale entries in the table. 
  442.          */  
  443.         private void expungeStaleEntries() {  
  444.             Entry[] tab = table;  
  445.             int len = tab.length;  
  446.             for (int j = 0; j < len; j++) {  
  447.                 Entry e = tab[j];  
  448.                 if (e != null && e.get() == null)  
  449.                     expungeStaleEntry(j);  
  450.             }  
  451.         }  
  452.     }  
  453. }  

<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值