首页 > 代码库 > ThreadLocal线程局部变量
ThreadLocal线程局部变量
1.ThreadLocal说明
线程内的共享数据:方法,表达式或者是模块,当他们在同一线程上运行,他们访问同一变量,应该访问的是同一数据。将数据与线程绑定到一起。换句话说,我线程内的事在我的线程内完成,不受其他线程的影响。线程内共享同一数据对象。即在线程内共享,在线程外独立。
public Map<Thread,Integer> threadData=http://www.mamicode.com/new HashMap
ThreadLocal:就相当于一个map,直接向当前线程存取数据。newThreadLocal.set()/get,对于同一个Thread对象而言,一个ThreadLocal对象只能封装一个数据,要封装两个数据则需要两个ThreadLocal独享,若是要封装一百个数据,那么先定义一个对象封装一百个ThreadLocal对象,然后封装这个对象。
ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。2.ThreadLocal与synchronized的区别
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
3.ThreadLocal使用的一般步骤
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
4.应用code演示
public class ThreadLocalTest { private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();// 多线程共享数据 public static void main(String[] args) { for (int i = 0; i < 5; i++) { // 多个线程往该threadLocal中存入值 new Thread(new Runnable() { @Override public void run() { // synchronized (ThreadLocalTest.class) { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data :" + data); threadLocal.set(data); MyThreadScopeData.getThreadInstance().setName( "name" + data); MyThreadScopeData.getThreadInstance().setAge(data); // 多个类中读取threadLocal的值,可以看到多个类在同一个线程中共享同一份数据 new A().get(); new B().get(); // } } }).start(); } } /** * 模拟业务模块A * * @author Administrator * */ static class A { public void get() { int data = threadLocal.get(); System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out .println("A from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + "," + myData.getAge()); } } /** * 模拟业务模块B * * @author Administrator * */ static class B { public void get() { int data = threadLocal.get(); System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out .println("B from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + "," + myData.getAge()); } } } class MyThreadScopeData { private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); public static MyThreadScopeData getThreadInstance() { MyThreadScopeData instance = map.get(); if (instance == null) { instance = new MyThreadScopeData(); map.set(instance); } return instance; } private String name; private int age; public String getName() { return name; } public void setName(String name) { System.out.println(Thread.currentThread().getName() + " setName :" + name); this.name = name; } public int getAge() { return age; } public void setAge(int age) { System.out .println(Thread.currentThread().getName() + " setAge :" + age); this.age = age; } }控制台输出结果:
Thread-3 has put data :-1350986975 Thread-1 has put data :-1681440308 Thread-2 has put data :-1348632509 Thread-0 has put data :1315014774 Thread-4 has put data :-129193035 Thread-3 setName :name-1350986975 Thread-3 setAge :-1350986975 Thread-0 setName :name1315014774 Thread-0 setAge :1315014774 Thread-4 setName :name-129193035 Thread-4 setAge :-129193035 Thread-2 setName :name-1348632509 Thread-2 setAge :-1348632509 A from Thread-4 get data :-129193035 Thread-1 setName :name-1681440308 A from Thread-4 getMyData: name-129193035,-129193035 A from Thread-0 get data :1315014774 A from Thread-0 getMyData: name1315014774,1315014774 A from Thread-2 get data :-1348632509 A from Thread-2 getMyData: name-1348632509,-1348632509 A from Thread-3 get data :-1350986975 A from Thread-3 getMyData: name-1350986975,-1350986975 Thread-1 setAge :-1681440308 A from Thread-1 get data :-1681440308 B from Thread-4 get data :-129193035 B from Thread-3 get data :-1350986975 B from Thread-0 get data :1315014774 B from Thread-0 getMyData: name1315014774,1315014774 B from Thread-2 get data :-1348632509 B from Thread-2 getMyData: name-1348632509,-1348632509 B from Thread-4 getMyData: name-129193035,-129193035 A from Thread-1 getMyData: name-1681440308,-1681440308 B from Thread-3 getMyData: name-1350986975,-1350986975 B from Thread-1 get data :-1681440308 B from Thread-1 getMyData: name-1681440308,-1681440308
5.web拓展
每一个HTTP请求、都是一个独立的线程,有一个独立的ThreadLocal。利用该特性我们可以利用ThreadLocal进行、HTTP请求生命周期的暂时存取值,不同类之间进行传值。比如传递数据库连接等。至此我们在Web应用不用Scope的变量存放值可以利用以下几种手段:
request、ThreadLocal、session、application等。其作用域大家都知道、就不在此详细说明了。现在说明一下request和ThreadLocal的差别。
1)、存取值方式不同。
request根据KEY存取值、一个request可以存多个值。
ThreadLocal只能存一个值,ThreadLocal的get和set方法没有参数KEY。
2)、使用地方不一样。
request使用在表示层、一般在Action和Servlet中使用。
ThreadLocal在什么地方都可以、一般用在框架基类中比较多、比如存放当前的数据库连接等。
转载请声明出处!!!
ThreadLocal线程局部变量