ThreadLocal类实例详解

1.ThreadLocal实例

    Num类

    

class IncreaseNum {
	ThreadLocal<Integer> num = new ThreadLocal<Integer>();

	public Integer getNextNum() {
		if(num.get()==null){
			//初始化是0
			num.set(0);
		}else{
			num.set(num.get() + 1);
		}
		return num.get();
	}
}

 

 

   线程类

   

class IncreaseNumThread extends Thread {

	IncreaseNum entity;

	public IncreaseNumThread(IncreaseNum entity) {
		this.entity = entity;
	}

	@Override
	public void run() {
		for(int i=0;i<3;i++){
			System.out.println(Thread.currentThread().getName() + "的数字"+ entity.getNextNum());
		}

 

 

 

   测试类

   

public static void main(String[] args) {
		IncreaseNum entity = new IncreaseNum();
		IncreaseNumThread thread1 = new IncreaseNumThread(entity);
		IncreaseNumThread thread2 = new IncreaseNumThread(entity);
		IncreaseNumThread thread3 = new IncreaseNumThread(entity);
		thread1.start();
		thread2.start();
		thread3.start();
	}	}
}

   

 

   结果

Thread-2的数字0
Thread-2的数字1
Thread-0的数字0
Thread-1的数字0
Thread-1的数字1
Thread-1的数字2
Thread-0的数字1
Thread-0的数字2
Thread-2的数字2

    

 

    如果按照正常来说的话3个线程共享一个实例,数字应该从0-8,但是现在每个线程的数字都是从0-2.这就是ThreadLocal的作用。

 

2.ThreadLocal类介绍

    早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。

 

ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。

 

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

 

从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思

 

 

 API定义

 

该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。

 

主要方法get()

 

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
 }

 可以看出get方法和当前线程有关,用map来存储,当前线程作为key,然后赋值,当取值的时候取出来的和当前线程相关,而不会影响其他线程的值。

 

 

3.ThreadLocal和线程同步比较

  1)在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。

 2)ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal

   概括起来说,对于多线程资源共享的问题,同步机制采用了以时间换空间的方式,而ThreadLocal采用了以空间换时间的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

 

      

 

ThreadLocal的应用场景:

 

1)Spring使用ThreadLocal解决线程安全问题

 

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

 

2)分页信息的存储

 

   每次请求都带有自己的分页信息,这些请求是并发的,为了保证每次请求的分页信息相互不影响,可以采用ThreadLocal保证线程并发的安全。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值