ThreadLocal和线程的普通成员变量究竟有什么区别?

问题由来:

最近在看多线程的知识,有提到ThreadLocal是一种线程局部变量,每个线程都有相对独立的变量初始化拷贝,是一种以空间换时间的做法。
那么问题来了,
1. 它和在线程代码里直接写一个普通成员变量有什么区别呢?
2. 它真的能“以空间换时间”吗?

问题1的思考:

问题:它和在线程代码里直接写一个普通成员变量有什么区别呢?
ThreadLocal和线程的普通成员变量都是线程安全的,我觉得这是毫无疑问的。因为每个线程都有一个threadLocals,这个里面就是一个ThreadLocalMap,而ThreadLocal对象就是map的key。
这样就可以写出非常优雅的代码了,因为传入一个外部的ThreadLocal对象,或者是线程的static对象,只要你没有对它进行过初始化,那么你通过threadLocal.get()出来的就是null。这就表明,一个threadLocal对象在其他线程里面调用了set()赋值,并不会影响到另一个线程。
话又说回来了,ThreadLocal和线程的普通成员变量到底有什么区别呢?
我的理解是,普通成员变量的初始化对这个线程本身是高度耦合的,我必须要知道这个线程是哪个,必须知道这个普通成员变量名是什么才能进行赋值。
而ThreadLocal则不需要,只需要声明好泛型的类型,定义好初始化函数,或者在自己定义的getValue方法里判断ThreadLocal.get()==null?是则调用ThreadLocal.set()方法进行初始化。
就比如这个例子:

public class MyThreadLocal { 
        //定义了一个ThreadLocal变量,用来保存int或Integer数据 
        private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() { 
                @Override 
                protected Integer initialValue() { 
                        return 0; 
                } 
        }; 
        public Integer getNextNum() { 
                //将tl的值获取后加1,并更新设置t1的值 
                tl.set(tl.get() + 1); 
                return tl.get(); 
        } 
}
/** 
* 测试线程 
*/ 
public class TestThread extends Thread { 
        private MyThreadLocal tlt = new MyThreadLocal(); 

        public TestThread(MyThreadLocal tlt) { 
                this.tlt = tlt; 
        } 

        @Override 
        public void run() { 
                for (int i = 0; i < 3; i++) { 
                        System.out.println(Thread.currentThread().getName() + "\t" + tlt.getNextNum()); 
                } 
        } 
}
/** 
* ThreadLocal测试 
* 
* @author leizhimin 2010-1-5 10:43:48 
*/ 
public class Test { 
        public static void main(String[] args) { 
                MyThreadLocal tlt = new MyThreadLocal(); 
                Thread t1 = new TestThread(tlt); 
                Thread t2 = new TestThread(tlt); 
                Thread t3 = new TestThread(tlt); 
                Thread t4 = new TestThread(tlt); 
                t1.start(); 
                t2.start(); 
                t3.start(); 
                t4.start(); 

        } 
}

测试结果:

Thread-0  1 
Thread-1  1 
Thread-0  2 
Thread-1  2 
Thread-0  3 
Thread-1  3 
Thread-2  1 
Thread-3  1 
Thread-2  2 
Thread-3  2 
Thread-2  3 
Thread-3  3 

由此可见,线程的代码里根本就不需要对ThreadLocal里的变量的初始化操心,这些都可以由外部的工具类完成,而工具类里也不需要管是哪个线程调用的。
我觉得这就是ThreadLocal最强大的地方!

问题2的思考:

问题:它真的能“以空间换时间”吗?
我觉得这个一空间换时间是针对使用static sycronized的变量而言的。
有的线程要用到数据库连接的condition,或者是session。这些都是线程不安全的,如果一个类只有一个全局的static变量,那么是一定要用同步来控制的。
那在高并发环境下的阻塞等待是不能容忍的。
所以使用ThreadLocal可以在每个线程都能初始化一下,就解决了异步问题。
所以我觉得ThreadLocal所说的“以空间换时间”,是针对static sycronized的方式来说的。


这就是我对ThreadLocal的思考,可能有些问题,还请高手指教。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值