编写正确的并发程序,关键在于:在访问共享的可变状态时进行正确的管理;《Java并发编程实战》---线程安全性---加锁中加锁机制可以通过同步来避免多个线程在同一时刻访问相同的数据,本文介绍如何共享和发布对象,从而使他们可以安全的由多个线程同时访问;
1:发布与逸出
"发布"一个对象:使对象能够在当前作用域之外的代码中使用;例如,通过类的非私有方法返回对象的引用,或者通过公有静态变量发布对象;
“逸出”:当某个不应该发布的对象被发布时,这就是逸出;
下面这个在类的外部任何线程都可以访问public域,这样发布对象是不安全的,因为我们无法假设,其他线程不会修改这些域,从而造成类状态的错误;
public class Unsafepublish{
public static Set secrect;
public String[] states={“AK”,”AL”};
public void init(){
secrect=new HashSet();
}
public String[] getStates(){
return states;
}
}
还有一种逸出是在构造对象时发生的,它会使类的this引用发生逸出,从而使线程看到一个构造不完整的对象;
public class Escape{
private int thisCanBeEscape = 0;
public Escape(){
new InnerClass();
}
private class InnerClass {
public InnerClass() {
//这里可以在Escape对象完成构造前提前引用到Escape的private变量
System.out.println(Escape.this.thisCanBeEscape);
}
}
public static void main(String[] args) {
new Escape();
}
}
2:线程封闭
3:不变性
4:安全发布
5:安全的共享对象
在并发程序中使用和共享对象时,可以使用一些使用策略:
1:线程封闭:线程封闭的对象只能由一个线程拥有,对象被封闭到该线程中,并且只能由整个线程修改
2:只读共享:在没有额外同步的情况下,共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它,共享的只读对象包括不可变对象和事实不可变对象。
3:线程安全共享:线程安全的对象在其内部实现同步,因此多个线程可以通过对象的公有接口来进行访问而不需进一步的同步
4:保护对象:被保护的对象只能通过持有特定的锁来访问。保护对象包括封装在其他线程安全对象中的对象,以及已发布的并且有某个特定锁保护的对象;