3 对象的共享
2018-09-11 本文已影响3人
史小猿
3.1可见性
加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步
Volatile变量
当把变量定义为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者其他处理器不可见的地方,因此在读取volatile类型的变量总是会返回最新写入的值。
写入volatile变量相当于退出同步代码块,读取volatile变量相当于进入同步代码块
加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
当且仅当满足以下所有条件时,才应该使用volatile变量:
- 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
- 该变量不会与其他状态变量一起纳入不变性条件中。
- 在访问变量时不需要加锁
3.2发布与逸出
隐式this逸出和安全的对象构造的例子
/**
* ThisEscape
* <p/>
* Implicitly allowing the this reference to escape
*
* @author Brian Goetz and Tim Peierls
*/
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
}
void doSomething(Event e) {
}
interface EventSource {
void registerListener(EventListener e);
}
interface EventListener {
void onEvent(Event e);
}
interface Event {
}
}
利用final和工厂来防止this逸出
/**
* SafeListener
* <p/>
* Using a factory method to prevent the this reference from escaping during construction
*
* @author Brian Goetz and Tim Peierls
*/
public class SafeListener {
private final EventListener listener;
private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
};
}
public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
void doSomething(Event e) {
}
interface EventSource {
void registerListener(EventListener e);
}
interface EventListener {
void onEvent(Event e);
}
interface Event {
}
}
不过本人看了这个,还是不懂咋回事,不懂为什么this逸出了,参考了博客写了下边的例子就知道咋回事了
public class ThisEscape {
private String name = null;
public ThisEscape(EventSource source) {
source.registerListener(new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
});
name = "TEST";
}
void doSomething(Event e) {
System.out.println(this.name.toString());
}
interface EventSource {
void registerListener(EventListener e);
}
interface EventListener {
void onEvent(Event e);
}
interface Event {
}
public static void main(String[] args) {
EventSource e = new EventSource() {
public void registerListener(EventListener e) {
e.onEvent(null);
}
};
new ThisEscape(e);
}
}
执行结果

public class SafeListener {
private final EventListener listener;
private String name = null;
private SafeListener() {
listener = new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
};
name = "TEST";
}
public static SafeListener newInstance(EventSource source) {
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
void doSomething(Event e) {
System.out.println(this.name.toString());
}
interface EventSource {
void registerListener(EventListener e);
}
interface EventListener {
void onEvent(Event e);
}
interface Event {
}
public static void main(String[] args) throws InterruptedException {
EventSource es = new EventSource(){
public void registerListener(EventListener e){
e.onEvent(null);
}
};
// new ThisEscape(es);
SafeListener.newInstance(es);
}
}
执行结果

第一个例子,类没有初始化完全,就使用this 报了空指针异常,this逸出。
第二个例子,类完全初始化后,使用this 正常打印。
3.3线程封闭(todo)
例子 JDBC Connection,Swing
栈封闭
引用被封闭在了方法中
ThreadLocal类