ThreadLocal与局部变量

ThreadLocal和线程局部变量有什么区别,我们先看一段代码,如下:

public class ThreadLocalLearn {

	static ThreadLocal<IntHolder> tl = new ThreadLocal<IntHolder>(){

		protected IntHolder initialValue() {
			
			return new IntHolder();
		}
		
	};
	
	public static void main(String args[]) {
		
		for(int i=0; i<5; i++) {
			
			Thread th = new Thread(new ThreadTest(tl, i));
			th.start();
		}
	}
}

class ThreadTest implements Runnable{

	ThreadLocal<IntHolder> tl ; //threadlocal变量
	int i;
	int a = 3; //线程局部变量

	public ThreadTest(ThreadLocal<IntHolder> tl, int i) {
		super();
		this.tl = tl;
		this.i = i;
	}

	@Override
	public void run() {
		
		tl.get().increAndGet();
		a++;
		System.out.println(tl.get().getA() + " ");
		System.out.println("a : " + a);
	}
	
}

class IntHolder{
	
	int a = 1;

	public int getA() {
		return a;
	}

	public void setA(int a) {
		this.a = a;
	}
	
	public int increAndGet() {
		
		return ++a;
	}
}

代码的运行结果如下:

2 
a : 4
2 
a : 4
2 
a : 4
2 
a : 4
2 
a : 4

可以看到,局部变量和ThreadLocal起到的作用是一样的,保证了并发环境下数据的安全性。那就是说,完全可以用局部变量来代替ThreadLocal咯,这样想法对么?我们看一看官方对于ThreadLocal的描述:

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

翻译起来就是

ThreadLocal提供的是一种线程局部变量。这些变量不同于其它变量的点在于每个线程在获取变量的时候,都拥有它自己相对独立的变量初始化拷贝。ThreadL:ocal的实例一般是私有静态的,可以做到与一个线程绑定某一种状态。PS:有更好的翻译请指教。

      所以就这段话而言,我们知道ThreadLocal不是为了满足多线程安全而开发出来的,因为局部变量已经足够安全。ThreadLocal是为了方便线程处理自己的某种状态。
      可以看到ThreadLocal实例化所处的位置,是一个线程共有区域。好比一个银行和个人,我们可以把钱存在银行,也可以把钱存在家。存在家里的钱是局部变量,仅供个人使用;存在银行里的钱也不是说可以让别人随便使用,只有我们以个人身份去获取才能得到。所以说ThreadLocal封装的变量我们是在外面某个区域保存了处于我们个人的一个状态,只允许我们自己去访问和修改的状态。
      ThreadLocal同时提供了初始化的机制,在实例化时重写initialValue()方法,便可实现变量的初始化工作

	//method 1
	static ThreadLocal<IntHolder> tl = new ThreadLocal<IntHolder>(){

		protected IntHolder initialValue() {
			
			return new IntHolder();
		}
		
	};
	//method 2
	IntHolder  intHolder = new IntHolder();
	static ThreadLocal<IntHolder> tl = new ThreadLocal<IntHolder>(){

		protected IntHolder initialValue() {
			
			return intHolder;
		}
		
	};

      方法一和方法二都可以实现初始化工作,但是方法二不能保证线程变量的安全性,因为引用拷贝指向的是同一个实例,对引用拷贝的修改,等同于对实例的修改。

方法二的样例
方法一的样例

      当然,也可以在判断ThreadlLocal获取数据为空时,在线程内部为ThreadLocal实例化一个数据。如下:

if(null == tl.get()) {
			
	tl.set(new IntHolder());
}

      为什么我们需要ThreadLocal来实现在自身内部外创建一个有关自己的状态呢?其实可以完全使用参数传递内部参数,就像我在自己随便放钱一样!这里要注意的是,我们定义一个方法的时候,并不是参数越多越好,有些共有参数,我们应该尽量设为全局,便于系统的可维护性与可扩展性。另一个角度考虑,银行也有其存在的价值,ThreadLocal会简化我们的编程,毕竟它是安全的。

根据ThreadLocal原理,我们自己实现一个:

import java.util.concurrent.ConcurrentHashMap;

public class ThreadLocalVar<T> {

	public T initVaribale() {
		
		return null;
	}
	
	volatile ConcurrentHashMap<Thread, T> map = new ConcurrentHashMap<Thread, T>(); 
	
	public void put(T t) {
		
		map.put(Thread.currentThread(), t);
	}
	
	public T get() {
		
		T value = map.get(Thread.currentThread());
		if(null == value) {
			
			T t = initVaribale();
			if(null == t) {
				return null;
			}
			map.put(Thread.currentThread(), t);
			return t;
		} else {
			
			return value;
		}
	}
}

有兴趣也可以去阅读jdk中ThreadLocal的源码~

===================
后记:20190622
`

局部变量可以保证的是方法内的线程私有,threadlocal可以保证对象级别的线程私有特性。因此局部变量在某些情况下不能保证并发安全性

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ThreadLocal局部变量都是用于解决多线程环境下的变量访问冲突问题,但是它们之间有一些区别。 1. 作用域不同 局部变量的作用域仅限于当前方法或代码块,一旦方法或代码块执行完毕,变量就会被销毁。而ThreadLocal变量的作用域是整个线程,即使方法执行完毕,ThreadLocal变量仍然存在于线程中,只有线程销毁时才会被销毁。 2. 变量共享方式不同 局部变量不会被多个线程共享,每个线程都有自己独立的变量副本,因此不需要考虑线程安全问题。而ThreadLocal变量则是每个线程都有自己独立的变量副本,因此可以在多个线程中共享数据,但是需要考虑线程安全问题。 3. 初始化方式不同 局部变量在定义时需要赋初值或者在使用前进行初始化。而ThreadLocal变量可以通过initialValue或者set方法进行初始化。 4. 内存占用不同 局部变量只在方法或代码块执行期间占用内存,方法执行完毕后就会被销毁,不会对内存造成影响。而ThreadLocal变量会一直占用内存,直到线程被销毁,如果不及时释放可能会对内存造成影响。 总的来说,ThreadLocal局部变量都有各自的优缺点,需要根据具体的场景来选择使用哪种方式。如果需要在多个方法或代码块中共享数据,并且需要考虑线程安全问题,可以使用ThreadLocal。如果变量仅在当前方法或代码块中使用,并且不需要考虑线程安全问题,可以使用局部变量

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值