一、概述
ThreadLocal的名称比较容易让人误解,会认为其是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量。
其设计的初衷是为了解决多线程编程中的资源共享问题。提起这个,大家一般会想到synchronized,synchronized采取的是“以时间换空间”的策略,本质上是对关键资源上锁,让大家排队操作。而ThreadLocal采取的是“以空间换时间”的思路,为每个使用该变量的线程提供独立的变量副本,在本线程内部,它相当于一个“全局变量”,可以保证本线程任何时间操纵的都是同一个对象。
二、实例
下面用一个实例阐述ThreadLocal的使用方法
创建一个Context类,其中含有transactionId属性。
1 package com.vigar; 2 3 public class Context { 4 5 private String transactionId = null; 6 7 public String getTransactionId() { 8 return transactionId; 9 } 10 11 public void setTransactionId(String transactionId) { 12 this.transactionId = transactionId; 13 } 14 }
创建MyThreadLocal做为容器,将一个Context对象保存于ThreadLocal中
1 package com.vigar; 2 3 public class MyThreadLocal { 4 public static final ThreadLocal userThreadLocal = new ThreadLocal(); 5 public static void set(Context user) { 6 userThreadLocal.set(user); 7 } 8 9 public static void unset() { 10 userThreadLocal.remove(); 11 } 12 13 public static Context get() { 14 return (Context)userThreadLocal.get(); 15 } 16 }
多线程客户端程序,用于测试
1 package com.vigar; 2 3 import java.util.Random; 4 5 public class ThreadLocalDemo extends Thread { 6 7 public static void main(String[] args) { 8 Thread threadOne = new ThreadLocalDemo(); 9 threadOne.start(); 10 Thread threadTwo = new ThreadLocalDemo(); 11 threadTwo.start(); 12 } 13 14 @Override 15 public void run() { 16 // 线程 17 Context context = new Context(); 18 Random random = new Random(); 19 int age = random.nextInt(100); 20 context.setTransactionId(String.valueOf(age)); 21 22 System.out.println("set thread ["+getName()+"] contextid to " + String.valueOf(age)); 23 // 在ThreadLocal中设置context 24 MyThreadLocal.set(context); 25 /* note that we are not explicitly passing the transaction id */ 26 try { 27 Thread.sleep(1000); 28 } catch (InterruptedException e) 29 { 30 e.printStackTrace(); 31 } 32 33 new BusinessService().businessMethod(); 34 MyThreadLocal.unset(); 35 } 36 }
模拟业务层,在某处读取context对象
1 package com.vigar; 2 public class BusinessService { 3 public void businessMethod() { 4 Context context = MyThreadLocal.get(); 5 System.out.println(context.getTransactionId()); 6 } 7 }
程序输出:
set thread [Thread-0] contextid to 32 set thread [Thread-1] contextid to 89 32 89
三、总结
ThreadLocal使用步骤
1.建立ThreadLocal容器对象A,其中对需要保存的属性进行封装。并提供相应的get/set方法(全部为static)
2.在客户端程序中,用A.setxxx, A.getXXX访问相应数据,即可保证每个线程访问的是自己独立的变量
参考文献:
1. 深入研究java.lang.ThreadLocal类_leizhimin_51CTO博客
2. http://veerasundar.com/blog/2010/11/java-thread-local-how-to-use-and-code-sample/
分类: corejava-基础, java底层, 并发编程
标签: threadlocal