ThreadLocal原来是这样啊~~

在这里给大家推荐一篇博客:http://my.oschina.net/lichhao/blog/111362

ThreadLocal大体的代码:

package java.lang;
import java.lang.ref.*;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

public class ThreadLocal<T> {
   
    private final int threadLocalHashCode = nextHashCode();

    protected T initialValue() {
        return null;
    }

    public ThreadLocal() {
    }

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

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
     
     static class ThreadLocalMap {

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

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
     
        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);
        }

      
        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) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) 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++;
                    }
                }
            }
        }

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

        private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

        /**
         * Remove the entry for key.
         */
        private void remove(ThreadLocal<?> key) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                if (e.get() == key) {
                    e.clear();
                    expungeStaleEntry(i);
                    return;
                }
            }
        }
    }
}


ThreadLocal的get和set方法

重点看这两个方法

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

public void set(T value) {
	Thread t = Thread.currentThread();
	ThreadLocalMap map = getMap(t);
	if (map != null)
		map.set(this, value);
	else
		createMap(t, value);
}


ThreadLocal的getMap和createMap方法

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

void createMap(Thread t, T firstValue) {
	t.threadLocals = new ThreadLocalMap(this, firstValue);
}


ThreadLocalMap的set方法定义

private void set(ThreadLocal<?> key, Object value);

可以看到键值为ThreadLocal对象,value为要在线程间隔离的值的内容。


Thread线程类的threadLocals属性

注意t.threadLocals;在Thread类中,有这样一个属性

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

每个线程都有自己独立的ThreadLocalMap对象。

所以说,每个线程中都有一个独立的threadLocals,这个属性的类型正是ThreadLocalMap,用于保存和当前线程绑定的变量


ThreadLocal代码示例:

解释:

/**

 * 对这段代码的理解:

 * 假如我创建十个线程,在这十个线程执行过程中,有十个Student实例被创建,

 * 并且每个实例只和当前的线程绑定(通过线程的threadLocals属性)

 * 在一个线程的生命周期中,访问的Student实例都是同一个实例---通过ThreadLocal绑定的实例。

 * 在这十个线程中,对Student实例的访问都是隔离的,互不影响的,因为每个Student实例都是不同的实例,消除了竞争条件,消除了并发访问。

 * 如果当前线程想绑定多个变量,那么就是用多个ThreadLocal来进行相应的绑定。。

 * ThreadLocal的适用情况:如果多个线程并发访问的对象实例只允许,也只能创建那么一个,那就没有别的办法了,老老实实的使用同步机制来访问吧。。

 */

package threadlocal;

import java.util.Random;

/**
 * 对这段代码的理解:
 * 假如我创建十个线程,在这十个线程执行过程中,有十个Student实例被创建,
 * 并且每个实例只和当前的线程绑定(通过线程的threadLocals属性)
 * 在一个线程的生命周期中,访问的Student实例都是同一个实例---通过ThreadLocal绑定的实例。
 * 在这十个线程中,对Student实例的访问都是隔离的,互不影响的,因为每个Student实例都是不同的实例,消除了竞争条件,消除了并发访问。
 * 如果当前线程想绑定多个变量,那么就是用多个ThreadLocal来进行相应的绑定。。
 * ThreadLocal的适用情况:如果多个线程并发访问的对象实例只允许,也只能创建那么一个,那就没有别的办法了,老老实实的使用同步机制来访问吧
 */
public class ThreadLocalDemo2 {

    //创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
    private final static ThreadLocal<Student> studentLocal = new ThreadLocal();
    //可以定义多个ThreadLocal,绑定多个变量

    public static void main(String args[]) {
        for (int i = 0; i < 2; i++) {
            final int finalI = i;
            Thread t = new Thread() {
                public void run() {
                    //获取当前线程的名字
                    String currentThreadName = Thread.currentThread().getName();
                    System.out.println(currentThreadName + " is running!");
                    //产生一个随机数并打印
                    Random random = new Random();
                    int age = random.nextInt(100);
                    System.out.println("thread " + currentThreadName + " set age to:" + age);

                    //在当前线程第一个调用get方法,返回值肯定为null
                    Student student = studentLocal.get();
                    if (student == null) {
                        student = new Student();
                        student.setAge(age);
                        student.setName("stu-" + finalI);
                        studentLocal.set(student); //和当前线程绑定一个实例
                    }
                    System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge() + " stu name:" + student.getName());

                    Student sss = studentLocal.get();//在当前线程再次访问和当前线程绑定的Student实例,在当前线程第二次调用该方法。。。。

                    System.out.println("thread " + currentThreadName + " second read age is:" + sss.getAge() + " stu name:" + student.getName());
                }
            };
            t.start();
        }
    }
}

运行结果:

Thread-1 is running!
Thread-0 is running!
thread Thread-0 set age to:80
thread Thread-1 set age to:72
thread Thread-0 first read age is:80 stu name:stu-0
thread Thread-1 first read age is:72 stu name:stu-1
thread Thread-0 second read age is:80 stu name:stu-0
thread Thread-1 second read age is:72 stu name:stu-1

=====END=====

你可能感兴趣的:(本地线程、封闭线程)