现在的位置: 首页 > 综合 > 正文

多线程7:线程封闭

2013年03月01日 ⁄ 综合 ⁄ 共 1718字 ⁄ 字号 评论关闭

当访问共享可变数据时,通常需要使用同步,同步是需要消耗性能的。

一种避免使用同步的方式就是不共享数据。如果数据都被封闭在各自的线程之中,就不需要同步。这种通过将数据封闭在线程中而避免使用同步的技术称为线程封闭。

1,Ad-hoc线程封闭

维护线程封闭性的职责完全由程序实现来承担,是非常脆弱的,因为没有任何一种语言特性,比如可见性修饰符或者局部变量,可以将对象封闭至目标线程上。

2,栈封闭

局部变量的固有属性之一就是封闭在执行线程之中,他们位于执行线程的栈中,其他线程无法访问这个栈。

 

3,使用ThreadLocal类

ThreadLocal<T>在每一个线程上创建一个T的副本,副本之间彼此独立,互不影响

概念上ThreadLocal<T>相当于Map<Thread,T>(并非是这么实现的),这些特定于线程的T保存在各自的线程对象中,当线程终止时这些值会作为垃圾回收

public class Task implements Runnable {
	private static ThreadLocal<Double> value = new ThreadLocal<Double>(){
		@Override
		protected Double initialValue() {
			return Math.random();
		}
	};
	
	public void run() {
		System.out.println(value.get());
	}
}
public class Test {
	public static void main(String[] args) {
		Task t = new Task();
		Thread td1 = new Thread(t);
		Thread td2 = new Thread(t);
		td1.start();
		td2.start();
	}
}

运行结果:

0.5331258124754218
0.5878812452143902

每个线程的value值是相互独立的

ThreadLocal类的4个方法:

initialValue
protected T initialValue()返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。 

该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。 

返回:
返回此线程局部变量的初始值
--------------------------------------------------------------------------------
get
public T get()返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。 

返回:
此线程局部变量的当前线程的值
--------------------------------------------------------------------------------
set
public void set(T value)将此线程局部变量的当前线程副本中的值设置为指定值。大部分子类不需要重写此方法,它们只依靠 initialValue() 方法来设置线程局部变量的值。 

参数:
value - 存储在此线程局部变量的当前线程副本中的值。
--------------------------------------------------------------------------------
remove
public void remove()移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法。 

 

4,单线程

当某个对象封闭在一个线程中时,线程是安全的,即使被封闭的对象本身不是线程安全的。

抱歉!评论已关闭.