您的位置:首页 > 编程语言 > Java开发

[Java] ThreadLocal相关内容

2012-10-18 20:31 453 查看
当谈到线程时,必然要关注多个线程对同一个资源的访问。比如某个线程要读一个变量,为了保证它在读的时候不被其它线程执行写操作,所以要加一个只读锁,这样其它线程就无法再加只写锁或读写锁,但是如果其它线程这时也要读它,可以再加只读锁。多个线程可以同时读这个变量,但是每次只有一个线程可以来写这个变量。这就是线程通过加锁的机制来访问变量。这种情况也就是同一个变量被多个线程共享,所以必须通过加锁进行同步。

看了ThreadLocal的源码,发现和它相关的还有ThreadLocalMap和Thread。对Thread都应该比较熟悉,就是一个线程。ThreadLocalMap从表面上看就是一个ThreadLocal的Map,它里面保存的是多个ThreadLocal->Value(即从ThreadLocal到Value的映射,ThreadLocal用作键,Value是对应的值)。它们之间的关系是,Thread里面定义了一个ThreadLocalMap的变量threadLocals,并且没有进行初始化。当你在一个线程里面第一次访问ThreadLocal时,这个线程的threadLocals变量被初始化为ThreadLocalMap的对象。然后ThreadLocal的对象和对应的值就被存储到变量threadLocals里面。同一个线程可以访问多个ThreadLocal对象,它们和对应的值都存储在同一个变量threadLocals里面。换言之,一个线程有一个ThreadLocalMap类型的变量threadLocals,它里面保存了多个ThreadLocal的对象到对应值的映射。这就是一个线程访问多个ThreadLocal。同样,一个ThreadLocal也可以被多个线程访问,这样每一个线程的ThreadLocalMap类型的变量threadLocals里面都存储了ThreadLocal到对应值的映射。把上面两种情况结合起来,就是多个线程访问多个ThreadLocal。

我们定义了一个ThreadLocal变量,每一个线程在访问它时,都会把这个变量和它对应的值放到线程里面,所以每个线程在读写时都是操作线程内部自己的拷贝。多个线程同时访问ThreadLocal时也不会有问题,我们定义的ThreadLocal变量并没有在线程间共享,而是每个线程自己拷贝了一份。所以不存在加锁和同步问题,当线程完成时,这个本地拷贝会随线程一起释放掉。

下面是一个简单的示例:

public static void main(String[] args) {

final ThreadLocal<Integer> tl = new ThreadLocal<Integer>();

new Thread(new Runnable(){
public void run() {
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get());
tl.set(10);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": set = " + 10);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get());
}}).start();

new Thread(new Runnable(){
public void run() {
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get());
tl.set(20);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": set = " + 20);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get());
}}).start();

new Thread(new Runnable(){
public void run() {
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get());
tl.set(30);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": set = " + 30);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get());
}}).start();

final ThreadLocal<Integer> tl0 = new ThreadLocal<Integer>();
final ThreadLocal<Integer> tl1 = new ThreadLocal<Integer>();
final ThreadLocal<Integer> tl2 = new ThreadLocal<Integer>();

new Thread(new Runnable(){
public void run() {
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl0.get = " + tl0.get());
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl1.get = " + tl1.get());
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl2.get = " + tl2.get());
tl0.set(10);
tl1.set(20);
tl2.set(30);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl0.set = " + 10);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl1.set = " + 20);
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl2.set = " + 30);

System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl0.get = " + tl0.get());
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl1.get = " + tl1.get());
System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl2.get = " + tl2.get());

}}).start();
}


运行结果如下:

Thread ID = 7: get = null

Thread ID = 7: set = 10

Thread ID = 7: get = 10

Thread ID = 9: get = null

Thread ID = 9: set = 30

Thread ID = 9: get = 30

Thread ID = 8: get = null

Thread ID = 8: set = 20

Thread ID = 8: get = 20

Thread ID = 10: tl0.get = null

Thread ID = 10: tl1.get = null

Thread ID = 10: tl2.get = null

Thread ID = 10: tl0.set = 10

Thread ID = 10: tl1.set = 20

Thread ID = 10: tl2.set = 30

Thread ID = 10: tl0.get = 10

Thread ID = 10: tl1.get = 20

Thread ID = 10: tl2.get = 30

如果文章有什么不对地方,欢迎指出!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: