JAVA并发编程笔记五


访问共享的、可变的数据要求使用同步。一个可以避免同步的方式就是不共享数据。如果数据仅在单线程中被访问,就不需要任何同步。线程封闭技术是实现线程安全的最简单的方式之一。

Ad-hoc线程限制是指维护线程限制性的任务全部落在实现上的这种情况。
栈限制是线程限制的一种特例,在栈限制中,只有通过本地变量才可以触及对象。本地变量本身就被限制在执行线程中,它们存在于执行线程栈。其他线程无法访问这个栈。

通过下面的例子来理解栈限制

public int loadTheArk(Collection<Animal> candidates){
	SortedSet<Animal> animals;
	int numPairs = 0;
	Animal candidate = null;
	//animals 被限制在方法中们不要让它们逸出!
	animals = new TreeSet<Animal>(new SpeciesGenderComparator());
	animals.addAll(candidates);
	for(Animal a : animals){
		if(candidate == null || !candidate.isPotentialMate(a))
			candidate =a;
		else{
		ark.load(new AnimalPair(candidate, a));
		++numPairs;
		candidate = null;
		}
	}
	return numPairs;
}
维护对象引用的栈限制,需要程序员多一些付出,来确保应用的对象没有逸出。在loadTheArk中,我们势力化一个TreeSet对象animals,并且保存了一个到animals中一个元素的引用。此时只有一个引用指向集合animals,因此它被限制在保存本地变量的执行线程中。但是,倘若我们发布了到集合animals的引用,那将会破坏限制性,也导致了animals对象的逸出。


ThreadLocal
ThreadLocal变量通常用于防止在基于可变的单体或全局变量的设计中,出现(不正确)共享。比如数据连接的Connection。


不可变性
创建后状态不能被修改的对象叫做不可变对象。不可变对象天生就是线程安全。
在java中可以使用final关键词来修饰,是对象变成不可变对象。
只有满足如下状态一个对象才是不可变的:
1.它的状态不能在创建后再被修改
2.所有域都是final类型
3.它被正确创建(创建期间没有发生this引用的逸出)
构造于底层可变对象之上的不可变类的例子:

public final class ThreeStooges{
	private final Set<String> stooges = new HashSet<String>();

	public ThreeStooges(){
		stooges.add("Moe");
		stooges.add("Larry");
		stooges.add("Curly");
	}
	public boolean isStooge(String name){
		return stooges.contains(name);
	}

}
不可变对象可以在没有额外同步的情况下,安全地用于任意线程,甚至发布它们时亦不需要同步。


安全发布的模式
为了安全地发布对象,对象的引用以及对象的状态必须同时对其他线程可见。
一个正确创建的对象可以通过下列条件安全地发布:
1.通过静态初始化器初始化对象的应用
2.将它的引用存储到volatile域或AtomicReference
3.将它的引用存储到正确创建的对象的final域中
4.或者将它的引用存储到有所正确保护域中
线程安全库中的容器提供了如下线程安全保证
1.置入Hashtable,synchronizedMap,ConcurrentMap中的主键以及键值,会安全地发布到可以从Map获得它们的任意线程中,无论是直接获得还是通过迭代器(iterator)获取
2.置入Vector,CopyOnWriteArrayList,CopyOnWriteArraySet,synchronizedList,synchronizedSet中的元素,会安全地发布到可以从容器中获得它的任意线程中
3.置入BlockingQueue或者ConcurrentLinkQueue的元素,会安全地发布到可以从队列中获得它的任意线程中。


安全地共享对象
在并发程序中,使用对象的一些最有效的策略如下:
1.线程限制:一个线程限制的对象,通过限制在线程中,而被线程独占,且只能被占有它的线程修改。
2.共享只读:一个共享的只读对象,在没有额外同步的情况下,可以被被多个线程并发访问,但是任何线程都不能修改它,共享只读对象包括可变对象与高效不可变对象。
3.共享线程安全:一个线程安全的对象在内部进行同步,所以其他线程无须额外同步,就可以通过公共接口随意地访问它。
4.被守护的:一个被守护的对象只能通过特定的锁来访问。被守护的对象包括哪些被线程安全对象封装的对象,和一直被特定的锁保护起来的已发布对象。

参考资料:

《JAVA并发编程实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值