ThreadLocal线程局部变量

1.ThreadLocal说明

线程内的共享数据:方法,表达式或者是模块,当他们在同一线程上运行,他们访问同一变量,应该访问的是同一数据。将数据与线程绑定到一起。换句话说,我线程内的事在我的线程内完成,不受其他线程的影响。线程内共享同一数据对象。即在线程内共享,在线程外独立。

public Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();threadData.put(Thread.currentthread,data);

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在什么地方都可以、一般用在框架基类中比较多、比如存放当前的数据库连接等。

转载请声明出处!!!

时间: 2024-11-09 15:20:08

ThreadLocal线程局部变量的相关文章

Java中线程局部变量ThreadLocal使用教程及源码分析

在Java多线程编程中有时候会遇见线程本地局部变量ThreadLocal这个类,下面就来讲讲ThreadLocal的使用及源码分析. ThreadLocal 是Thread Local Varial(线程局部变量)的意思,每个线程在使用线程局部变量的时候都会为使用这个线程局部变量的线程提供一个线程局部变量的副本,使得每个线程都可以完全独立地操作这个线程局部变量,而不会与其他线程发生冲突,从线程的角度来看,每个线程都好像独立地拥有了这个线程局部变量.这样,看似每个线程都在并发访问同一个资源(线程局

ThreadLocal为什么称作线程局部变量

一.RTFSC java.lang.ThreadLocal<T>的具体实现 那么到底ThreadLocal类是如何实现这种"为每个线程提供不同的变量拷贝"的呢?先来看一下ThreadLocal的set()方法的源码是如何实现的: [java] view plaincopyprint? /** * Sets the current thread's copy of this thread-local variable * to the specified value.  Mo

JAVA并发编程之线程局部变量

共享数据是并发程序最核心的问题之一,对于继承Thread类或者实现Runnable接口的对象来说尤其重要. 如果创建的对象实现了Runnable接口的类的实例,用它作为传入参数,并创建多个线程对象并启动这些线程,那么所有的线程将共享相同的属性.如果在一个线程中改变一个属性,所有线程都会被这个改变影响. 在某种情况下,这个对象的属性不需要被所有线程共享.JAVA提供了一个比较好的机制,即线程局部变量(Thread-Local Variable). 我们写一个简单的DEMO,一是具有刚才提到的问题,

线程局部变量的使用

共享数据是并发程序最核心的问题之一,对于继承了Thread类或者实现了Runnable接口的对象来说尤其重要.如果创建的对象是实现了Runnable接口的类的实例,用它作为传入参数创建多个线程对象并启动这些线程,那么所有的线程将共享相同的属性.也就是说,如果你在一个线程中改变了一个属性,所有线程都会被这个改变影响. 在某种情况下,这个对象的属性不需要被所有线程共享.Java并发API提供了一个干净的机制,即线程局部变量(Thread-Local Variable),其具有很好的性能. 这里我们将

ThreadLocal(线程绑定)

为保证在DAO层里的操作都在同一事务里,我们曾使用以参数的形式将Connection向下传递的方式,而ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个connection连接).那么ThreadLocal是如果做到的呢?它和同步锁的不同在哪里? 是什么: 对于ThreadLocal看英文单词我们很容易理解为一个线程的本地实现,但是它并不是一个Thread,而是thread

并发组件之一:ThreadLocal线程本地变量

一.简介  ThreadLocal从字面上进行理解很容易被大部分人认为是本地线程,然而ThreadLocal并不是一个Thread,可以说它只是一个容器,而它装的内容又是Thread的局部变量.很多文章都会把ThreadLocal当作是解决高并发下线程不安全的一种做法,然而ThreadLocal并不是为了解决并发安全甚至可以这么说,它与真正的并发安全背道而驰.并发安全是指多个线程对同一个对象进行操作而导致的不安全,但是ThreadLocal在每个线程内部保存了一份该对象,使得每个线程都操作自己内

[Python]threading local 线程局部变量小测试

概念 有个概念叫做线程局部变量,一般我们对多线程中的全局变量都会加锁处理,这种变量是共享变量,每个线程都可以读写变量,为了保持同步我们会做枷锁处理.但是有些变量初始化以后,我们只想让他们在每个线程中一直存在,相当于一个线程内的共享变量,线程之间又是隔离的.python threading模块中就提供了这么一个类,叫做local. 多线程中共享变量和局部变量的区别我画两个小图,简单描述下(作图能力一般,请见谅,概念性的东西大家可以google下,很多好文章) 全局变量 线程局部变量 对比: 下面是

转载 多线程开发时线程局部变量的使用

多线程开发时线程局部变量的使用 http://blog.csdn.net/zsxxsz/article/details/6284759 2011-03-28 22:37197人阅读评论(0)收藏举报 一.概述 现在多核时代多线程开发越来越重要了,多线程相比于多进程有诸多优势(当然也有诸多劣势).在早期C的库中,有许多函数是线程不安全的,因为内 部用到了静态变量,比如:char *strtok(char *s, const char *delim); 该函数内部就有一个静态指针,如果多个线程同时调

【java】ThreadLocal线程变量的实现原理和使用场景

一.ThreadLocal线程变量的实现原理 1.ThreadLocal核心方法有这个几个 get().set(value).remove() 2.实现原理 ThreadLocal在每个线程都会创建一个线程内对应的T的副本,本T数据可以在本线程内任何地方可以被使用.线程之间互相不影响,所以是线程安全的. 3.底层结构 ThreadLocal实现各个线程数据副本的存取,是通过操作它的内部类ThreadLocalMap,进行<k,v>键值对的存取和移除. 4.set(value)方法的底层 pub