解析ThreadLocal

(本文摘抄Spring3.X企业应用开发实战)

解决多线程中相同变量的并发访问冲突问题,通常是采用synchronized方式,即通过对象锁机制保证同一时间只有一个线程访问变量。但是,使用同步机制需要缜密分析什么时候对变量进行读写,锁定对象,释放对象,对编程要求高。
JDK提供了ThreadLocal从另外一个角度解决这个问题。ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线程访问同一数据的冲突,ThreadLocal提供线程安全的对象封装,编写代码时可以把不安全的变量封装到ThreadLocal中。

在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,这样ThreadLocal就为每一个线程维护变量的副本。ThreadLocal类支持泛型,其接口很简单,只有4个方法:
1.void set(T value)设置当前线程的线程局部变量的值。
2.public T get()该方法返回当前线程所对应的线程局部变量。
3.public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应4.该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
5.protected T initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(T)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。


下面给一个多个线程操作同一数据的例子:

package test;

public class ThreadLocalTest {
	
	public static void main(String args[]){
		SeqNum sn = new SeqNum();
		Client t1 = new Client(sn);
		Client t2 = new Client(sn);
		Client t3 = new Client(sn);
		t1.start();
		t2.start();
		t3.start();
	}
}

// 封装要操作的数字变量
class SeqNum{
	private static  ThreadLocal<Integer> num=new ThreadLocal<Integer>()
			{
		// 通过匿名内部类覆盖ThreadLocal的initValue方法
		public Integer initialValue(){
			return 0;
		}
	};
	
	public int getNext(){
		num.set(num.get()+1);
		return num.get();
	}		
}


class Client extends Thread{
	private SeqNum sn;

	public Client(SeqNum sn) {
		this.sn = sn;
	}
	public void run(){
		for(int i=0;i<3;i++){
			System.out.println("threa"+Thread.currentThread().getName()+"  sn"+sn.getNext());
		}
	}
}

输出为:

threaThread-0  sn1
threaThread-0  sn2
threaThread-0  sn3
threaThread-2  sn1
threaThread-1  sn1
threaThread-2  sn2
threaThread-2  sn3
threaThread-1  sn2
threaThread-1  sn3

课件各自的序号独立,没有发生相互干扰的情况。


Spring使用ThreadLocal解决线程安全问题,我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,而在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值