ThreadLocal源代码1

public class ThreadLocalTrxt {
    static ThreadLocal<Object> x1 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x2 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x3 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x4 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x5 = new ThreadLocal<Object>();

    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i = 0; i<5; i++) {
                        x1.set(i); //把x1设置到这个线程的threadLocals里面的table里面的Entry里面的referent里面去,还有i=0
                        x2.set(i); 
                        x3.set(i); 
                        x4.set(i); 
                        x5.set(i); 
                    }
                    Thread t = Thread.currentThread();
                    ThreadLocal<Object> x6 = new ThreadLocal<Object>();
                    x6.remove();
                    x1.remove();
                    x2.remove();
                    x3.remove();
                    x4.remove();
                    x5.remove();
                }
            }).start();
        }
    }
}
public class Test {

    public static void main(String[] args) {
        AtomicInteger hashCode = new AtomicInteger();
        int hash_increment = 0x61c88647;
        int size = 32;
        List <Integer> list = new ArrayList <> ();
        for (int i = 0; i < size; i++) {
            System.out.println(hashCode);
            hashCode.getAndAdd(hash_increment);
            System.out.println(hashCode);
            System.out.println(hashCode.intValue() & (size - 1));
            list.add(hashCode.intValue() & (size - 1));
        }
        System.out.println("original:" + list);
        Collections.sort(list);
        System.out.println("sort:    " + list);
        System.out.println(hash_increment);
    }
}

 

public class ThreadLocalTrxt {
    static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    int s = new Random().nextInt();
                    x.set(s);     //   ThreadLocal 设置值的时候,自动跟线程关联
                    System.out.println(x.get());    //  ThreadLocal 取值的时候,自动跟线程关联
                }
            }).start();
        }
    }
}
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);  // 返回null
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
threadLocals是ThreadLocalMap在线程Thread里面
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;  //  返回线程的threadLocals,是一个ThreadLocalMap类型,只不过这个类型在ThreadLocal里面定义
    }
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);    //this是ThreadLocal,调用x.set(s);的x
    }

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

 ThreadLocal设置值是设置到这个线程的threadLocals属性里面去了,并且ThreadLocal自己也在threadLocals里面。多个线程共用这个ThreadLocal

 
比如用到了线程池,线程一直运行就不会终止,那么线程就会一直存在着,thereadLocalMap就会一直存在,map里面的key和value也会一直在,但是由于theadLocalMap里面的key=theadLocal是弱引用(没有强引用就会回收),key(theadLocal)一旦gc了,value因为是强引用就回收不了了,就发生了内存泄漏(value没有用了但是一直不能回收,就是内存泄漏)。解决办法:set,remove,rehash方法中,扫描到key=null的entry,并发对应的value设置为null。如果这个线程一直不终止,set,remove,rehash方法也一直不调用,那么还是会内存泄漏。解决办法:规定不再使用theadLocal的时候,一定要remove(),比如拦截器里面设置了user信息,那么线程出去的时候一定要把user给remove掉。
如果在每个线程中ThreadLocal.set()进去的东西本来就是多线程共享的同一个对象,比如static对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。
例如在Spring中,如果可以使用RequestContextHolder,那么就不需要自己维护ThreadLocal,因为自己可能会忘记调用remove()方法等,造成内存泄漏。
DateTimeContextHolder类,RequestContextHolder类,看到里面用了ThreadLocal。
 

ThreadLocalMap的key是ThreadLocal,Value是set方法设置进来的值。
Entry是ThreadLocalMap的内部类,ThreadLocal和value2个属性组成。

 

 线程初始化时候:

public class ThreadLocalTrxt {
    static ThreadLocal<Object> x1 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x2 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x3 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x4 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x5 = new ThreadLocal<Object>();
    static ThreadLocal<Object> x6 = new ThreadLocal<Object>();

    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {//2个线程调用,则2个线程共享x1,x2,x3,x4,x5,x6。但是ThreadLocal里面没有属性(只是充当一个key),2个线程修改的时候,
                                    //修改的是线程内部的threadLocals。Thread和ThreadLocal是在一个包下的。不同线程相同的key(ThreadLocal)得到的可以是不同的value。
                @Override
                public void run() {
                    for(int i = 0; i<5; i++) {
                    x1.set(i); //把x1设置到这个线程的threadLocals里面的table里面的Entry里面的referent里面去,还有i=0
                    x2.set(i); //  重复调用会覆盖
                    x3.set(i); 
                    x4.set(i); 
                    x5.set(i); 
                    x6.set(i); 
                    }
                    Thread t = Thread.currentThread();
                    System.out.println(x1.get()); 
                    x1.remove(); 
                }
            }).start();
        }
    }
}

 

ThreadLocal无法解决线程安全问题。也就是说ThreadLocal是被各个线程共享的。 

 

posted @ 2019-05-23 14:32  无天666  阅读(231)  评论(0编辑  收藏  举报