欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
ThreadLocal源碼分析
 在閱讀《Java Concurrency In Practice》時(shí),書(shū)中提到ThreadLocal是一種更為規范常用的Thread Confine方式。于是想仔細分析一下ThreadLocal的實(shí)現方式。曾經(jīng)轉載了一篇關(guān)于ThreadLocal的文章:hi.baidu.com/gefforey520/blog/item/c3bb64fa4ad1779358ee902c.html,其中提到ThreadLocal的實(shí)現方式是聲明一個(gè)Hashtable,然后以Thread.currentThread()為key,變量的拷貝為value。今天閱讀源碼才知道實(shí)現方式已經(jīng)大為改變,下面來(lái)看代碼。
/**
* ThreadLocals rely on per-thread linear-probe hash maps attached to each
* thread (Thread.threadLocals and inheritableThreadLocals). The ThreadLocal
* objects act as keys, searched via threadLocalHashCode. This is a custom
* hash code (useful only within ThreadLocalMaps) that eliminates collisions
* in the common case where consecutively constructed ThreadLocals are used
* by the same threads, while remaining well-behaved in less common cases.
*/
private final int threadLocalHashCode = nextHashCode();

/**
* The next hash code to be given out. Updated atomically. Starts at zero.
*/
private static AtomicInteger nextHashCode = new AtomicInteger();

/**
* The difference between successively generated hash codes - turns implicit
* sequential thread-local IDs into near-optimally spread multiplicative
* hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647;

/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
/**
* Creates a thread local variable.
*/
public ThreadLocal() {
}
ThreadLocal只有三個(gè)變量,從構造函數知道,在創(chuàng )建一個(gè)ThreadLocal實(shí)例時(shí),只是調用nextHashCode方法將nextHashCode的值賦給實(shí)例的threadLocalHashCode,然后nextHashCode的值增加HASH_INCREMENT這個(gè)值。 因此ThreadLocal實(shí)例的變量只有threadLocalHashCode,而且是final的,用來(lái)區分不同的ThreadLocal實(shí)例。
再來(lái)看其get方法:
/**
* Returns the value in the current thread's copy of this thread-local
* variable. If the variable has no value for the current thread, it is
* first initialized to the value returned by an invocation of the
* {@link #initialValue} method.
* 
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T) e.value;
}
return setInitialValue();
}
其中調用getMap(Thread t)返回ThreadLocalMap,ThreadLocalMap是內部靜態(tài)類(lèi),部分代碼如下:
/**
* ThreadLocalMap is a customized hash map suitable only for maintaining
* thread local values. No operations are exported outside of the
* ThreadLocal class. The class is package private to allow declaration of
* fields in class Thread. To help deal with very large and long-lived
* usages, the hash table entries use WeakReferences for keys. However,
* since reference queues are not used, stale entries are guaranteed to be
* removed only when the table starts running out of space.
*/
static class ThreadLocalMap {

/**
* The entries in this hash map extend WeakReference, using its main ref
* field as the key (which is always a ThreadLocal object). Note that
* null keys (i.e. entry.get() == null) mean that the key is no longer
* referenced, so the entry can be expunged from table. Such entries are
* referred to as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;

Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}

/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;

/**
* The table, resized as necessary. table.length MUST always be a power
* of two.
*/
private Entry[] table;

/**
* The number of entries in the table.
*/
private int size = 0;

/**
* The next size value at which to resize.
*/
private int threshold; // Default to 0
Entry繼承WeakReference,通過(guò)其注釋并結合WeakReference的功能,我們知道:一旦沒(méi)有指向 key 的強引用, ThreadLocalMap 在 GC 后將自動(dòng)刪除相關(guān)的 entry。ThreadLocalMap采用數組來(lái)保存Entry,并且Entry中以ThreadLocal為key,初始大小為16.
        接著(zhù)看ThreadLocalMap的constructor:
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create one when we
* have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
/**
* Construct a new map including all Inheritable ThreadLocals from given
* parent map. Called only by createInheritedMap.
* 
* @param parentMap
*            the map associated with parent thread.
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];

for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
ThreadLocal key = e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
ThreadLocalMap有兩個(gè)構造函數,可以直接傳入ThreadLcoal-value對,也可以傳入一個(gè)ThreadLocalMap,傳入ThreadLocalMap的時(shí)候,會(huì )依次將其Entry存放在table中。接著(zhù)來(lái)分析get方法:
/**
* Get the entry associated with key. This method itself handles only
* the fast path: a direct hit of existing key. It otherwise relays to
* getEntryAfterMiss. This is designed to maximize performance for
* direct hits, in part by making this method readily inlinable.
* 
* @param key
*            the thread local object
* @return the entry associated with key, or null if no such
*/
private Entry getEntry(ThreadLocal key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
通過(guò)實(shí)例變量threadLocalHashCode算出下標,然后返回其值。set和remove方法類(lèi)似。
繼續看ThreadLocal類(lèi)的get方法,通過(guò)getMap(Thread t)返回ThreadLocalMap,然后從ThreadLocalMap中通過(guò)getEntry(ThreadLocal key) 取出值。下面繼續看getMap(Thread t)方法:
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* 
* @param t
*            the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
可以看出其返回的是線(xiàn)程的一個(gè)實(shí)例變量。由此可知Thread類(lèi)也持有ThreadLocalMap,這樣每個(gè)線(xiàn)程的變量都存放在自己的ThreadLocalMap中,可謂名符其實(shí)。
繼續看Thread類(lèi)如何操作ThreadLocalMap:
/*
* ThreadLocal values pertaining to this thread. This map is maintained by
* the ThreadLocal class.
*/
ThreadLocal.ThreadLocalMap threadLocals = null;

/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
Thread類(lèi)中聲明了兩個(gè)ThreadLocalMap變量,
/**
* Initializes a Thread.
* 
* @param g
*            the Thread group
* @param target
*            the object whose run() method gets called
* @param name
*            the name of the new Thread
* @param stackSize
*            the desired stack size for the new thread, or zero to indicate
*            that this parameter is to be ignored.
*/
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */

/*
* If there is a security manager, ask the security manager what to
* do.
*/
if (security != null) {
g = security.getThreadGroup();
}

/*
* If the security doesn't have a strong opinion of the matter use
* the parent thread group.
*/
if (g == null) {
g = parent.getThreadGroup();
}
}

/*
* checkAccess regardless of whether or not threadgroup is explicitly
* passed in.
*/
g.checkAccess();

/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}

g.addUnstarted();

this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
this.name = name.toCharArray();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = AccessController.getContext();
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;

/* Set thread ID */
tid = nextThreadID();
}
在init方法中,存在著(zhù)對inheritableThreadLocals的操作:
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
而ThreadLocal的createInheritedMap方法則是調用ThreadLocalMap類(lèi)傳入ThreadLocalMap參數的構造函數。
也就是說(shuō)在Thread類(lèi)中,當前線(xiàn)程會(huì )調用init方法去初始一個(gè)線(xiàn)程,而在init方法中,會(huì )將當前線(xiàn)程的inheritableThreadLocals拷貝給等待初始化的線(xiàn)程。這讓我聯(lián)想起unix/linux系統中,父線(xiàn)程會(huì )調用fork()函數生成一個(gè)子線(xiàn)程,而且會(huì )把父線(xiàn)程大部分的信息拷貝給子線(xiàn)程。
         最后來(lái)看Thread類(lèi)的exit方法:
/**
* This method is called by the system to give a Thread a chance to clean up
* before it actually exits.
*/
private void exit() {
if (group != null) {
group.remove(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
在線(xiàn)程真正終止前會(huì )執行這個(gè)方法,這個(gè)方法會(huì )把threadLocals和inheritableThreadLocals指向null。但我在Thread類(lèi)中并沒(méi)有看到對threadLocals的賦值,應該是通過(guò)ThreadLocal來(lái)設置的。
        寫(xiě)了個(gè)簡(jiǎn)單的Thread測試程序,只是想跟蹤一下上述兩個(gè)ThreadLocalMap變量的狀態(tài):
public class TimePrinter extends Thread {

public void run() {
while (true) {
try {
System.out.println(new Date(System.currentTimeMillis()));
} catch (Exception e) {
System.out.println(e);
}
}
}

static public void main(String args[]) {
TimePrinter tp1 = new TimePrinter();
tp1.start();
ThreadLocal t2 = new ThreadLocal();
t2.set("aaaaaaaaaaaaaaaaaaaaaaaa");
}
}
可以看到,啟動(dòng)一個(gè)線(xiàn)程,不停打印系統時(shí)間,然后通過(guò)ThreadLocal給當前線(xiàn)程添加一份字符串,觀(guān)察有:




inheritableThreadLocals中有一個(gè)Entry,但value為null,threadLocals中有三個(gè)Entry,其中兩個(gè)value不明,一個(gè)為T(mén)hreadLocal設置的值。不過(guò)我實(shí)在不知道其他三個(gè)Entry值是如何設置的,留個(gè)疑問(wèn)。
總結:ThreadLocal實(shí)例只有一個(gè)threadLocalHashCode值,ThreadLocal給各個(gè)線(xiàn)程設置的值都是存在各個(gè)線(xiàn)程threadLocals里 。相比Hashtable的實(shí)現方式,現在的方式更為合理。當一個(gè)線(xiàn)程終止時(shí),其inheritableThreadLocals和threadLocals均被置為null,于是通過(guò)TreadLocal也就無(wú)法訪(fǎng)問(wèn)這個(gè)線(xiàn)程;而當ThreadLocal被設置為null時(shí),Thread里threadLocals就會(huì )移除key為T(mén)hreadLocal的Entry。Hashtable的實(shí)現方式則無(wú)法實(shí)現這一點(diǎn)。最為關(guān)鍵的是Hashtable的實(shí)現需要同步,所帶來(lái)的性能損耗是很大的,而現在的方式則不需要同步。性能提升很大。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Java中的ThreadLocal深入理解 – 碼農網(wǎng)
Java面試必問(wèn):ThreadLocal終極篇 淦!
ThreadLocal的源碼分析
ThreadLocal 源碼解讀
深入理解 ThreadLocal
深入分析ThreadLocal
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久