Java并发——线程局部变量

1. 为什么要使用线程局部变量你?

如果创建的对象实现了Runnable接口的类的实例,用它作为传入参数,并创建多个线程对象并启动这些线程,那么所有的线程将共享相同的属性。如果在一个线程中改变一个属性,所有线程都会被这个改变影响。这样,不得不处理同步的问题。

要想把线程私有数据(如一个用户ID)和线程关联起来,可以使用线程局部变量 java.lang.ThreadLocal类

2. 什么是线程局部变量?

每个ThreadLocal的实例代表了一个线程局部变量,它为每一条访问线程提供了单独的存储槽(storage slot)。可以把它想象成具有多个槽的变量,然后每条线程可以在同一个变量中存储不同的值。并且,每条线程都只能 看到自己的值,而不会意识到其他线程在这个变量中也有自己的值。

声明方式:ThreadLocal<T>

3.构造函数和方法:

(1)ThreadLocal(): 创建了一个新的线程局部变量。

(2)T get(): 返回调用线程的存储槽中的值。如果当这个线程调用此方法时,值不存在,那么get()会调用 initialValue()方法。

(3)T initialValue(): 创建调用线程的存储槽并存入一个初始(默认)值。默认的初始值是null。

(4)void remove(): 清空调用线程的存储槽。在没有set()方法介入的情况下,如果紧随此方法之后调用get()方法,那么get()方法就会直接调用initialValue()。

(5)void set(T value):设置调用线程的存储槽上的值。

//使用线程局部变量关联不同用户的ID

public class ThreadLocalDemo {

	private static volatile ThreadLocal<String> userID = new ThreadLocal<>();
	
	public static void main(String[] args)
	{
		Runnable r = new Runnable()
				{
			         @Override
			         public void run()
			         {
			        	 String name = Thread.currentThread().getName();
			        	 if(name.equals("A"))
			        		 userID.set("foxtrot");
			        	 else
			        		 userID.set("charlie");
			        		 
			        	 System.out.println(name + " " + userID.get());
			         }
				};
				
		Thread t1 = new Thread(r, "A");
		Thread t2 = new Thread(r, "B");
		t1.start();
		t2.start();
	}
}

运行结果:

A foxtrot
B charlie

4. 存储在线程局部变量中的值都是相关的。当一个新的线程被创建出来,它会获得一个新的包含initialValue()值的存储槽。

当想要把值从父类传给子线程时,可以使用InheritableThreadLocal。

InheritableThreadLocal是ThreadLocal的子类,除了InheritableThreadLocal()构造方法,还有:

T childValue(T parentValue):在子线程被创建出来的时候,用父线程的值(即参数)计算出子线程的初始值。


//将一个对象从父线程传到子线程
public class InheritableThreadLocalDemo {

	private static volatile InheritableThreadLocal<Integer> intVal = new InheritableThreadLocal<Integer>();
	
	public static void main(String[] args)
	{
		Runnable rParent = new Runnable()
				{
			         @Override
			         public void run()
			         {
			        	 intVal.set(10);  //父线程在intVal中存储一个值为10的Integer
			        	 Runnable rChild = new Runnable()
			        			 {
			        		          @Override
			        		          public void run()
			        		          {
			        		        	  String name = Thread.currentThread().getName();
				        		           System.out.printf("%s %d%n",name,intVal.get());
			        		          }			        		  	 
			        			 };
			        	Thread thdChild = new Thread(rChild,"Child");
			        	thdChild.start();
			        	
			         }
				};
				
				new Thread(rParent).start();
	}
}

主线程创建了一条父线程,这条线程在intVal中存储了一个值为10的java.lang.Integer对象。父线程之后创建了一条子线程,这条线程访问intVal并取得父线程中的Integer对象。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值