关于threadlocal

来源:互联网 发布:程序员工作心得体会 编辑:程序博客网 时间:2024/05/16 05:47

  在网上看了很多关于threadlocal的文章,感觉大部分说的都是不明其意,关于threadlocal的作用也是众说纷纭,但最多的说法是threadlocal的作用是用于解决多线程并发问题,但自己经过测试,发现并不是那么简单,所以记录下来以供自己日后复习和参考。

     首先要确定的一点是theadlocal的出现并不是为了解决并发问题的,他的作用简单来讲应该是实现线程独有的全局变量这样一个概念。ThreadLocal之所以能使得各线程有各自独立的一个对象,不是通过对什么对象的拷贝或副本来实现的,而是通过每个线程中的new 对象 的操作来创建的对象(initialValue方法),每个线程创建一个,才能保持各线程之间互不干扰。

threadlocal的set方法如下  

/**     * Sets the current thread's copy of this thread-local variable     * to the specified value.  Most subclasses will have no need to     * override this method, relying solely on the {@link #initialValue}     * method to set the values of thread-locals.     *     * @param value the value to be stored in the current thread's copy of     *        this thread-local.     */    public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }

createMap方法

 /**     * Create the map associated with a ThreadLocal. Overridden in     * InheritableThreadLocal.     *     * @param t the current thread     * @param firstValue value for the initial entry of the map     * @param map the map to store.     */    void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }

        可以从上面看到完全没有什么做拷贝或是副本的操作,所以如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。 具体验证如下

package EX04;import java.util.HashMap;public class Test {static ThreadLocal<HashMap<String,String>> stringLocal = new ThreadLocal<HashMap<String,String>>();static HashMap<String,String> map = new HashMap<String,String>();public static void main(String[] args) throws InterruptedException {stringLocal.set(map);System.out.println("main >>> " +stringLocal.get().get("key"));stringLocal.get().put("key", "value1");Thread thread1 = new Thread() {public void run() {stringLocal.set(map);System.out.println("thread1 >>> " + stringLocal.get().get("key"));stringLocal.get().put("key", "value2");};};thread1.start();thread1.join();System.out.println("main >>> " + stringLocal.get().get("key"));}}
输出:

main >>> nullthread1 >>> value1main >>> value2
可以看到同一个static变量map,主线程修改可以影响thread1线程,thread1线程也可以影响主线程,验证结束。

最后重申,threadlocal的创建不是为了解决并发问题,而是为了作为线程内的全局变量去使用,比如数据库操作,如果一个事务中涉及多个 DAO 操作,而如果这些DAO中的Connection都是独立创建的话,就没有办法完成一个事务。但是如果放在 ThreadLocal 中就可以解决这个问题,当然他额外的好处就是,在使用过程中,别的线程(用户)也无法调用或者修改这个线程里connection对象。 



原创粉丝点击