首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Java 理论和实践 安全构造技术(2)

Java 理论和实践 安全构造技术(2)

不要隐式地暴露“this”引用在根本不使用         this 引用情况下,也有可能会造成逃脱的引用问题。非静态内部类维护着其父类的         this 引用的隐式副本,所以创建匿名的内部类实例,并将其传递给从当前线程外部可以看见的对象,会存在与暴露         this 引用本身所具有的所有相同的风险。考虑清单 4,它与清单 2 有同样的根本问题,但这里没有显式地使用         this 引用:      
清单 4. 使用匿名内部类时,不正确地公布了“this”
1
2
3
4
5
6
7
8
9
10
11
12
public class EventListener2 {
  public EventListener2(EventSource eventSource) {
    eventSource.registerListener(
      new EventListener() {
  public onEvent(Event e) {
          eventReceived(e);
        }
      });
  }
  public onEvent(Event e) {
  }
}




EventListener2 类和其类似代码  中的         EventListener 有同样的弊端:公布了对正在构造的对象的引用 ― 在这种情况下,是间接的 ― 另一个线程可以看见这个引用。如果打算创建         EventListener2 的子类,将会碰到同样的问题,即在子类构造函数完成之前会调用子类方法。      
不要从构造函数内启动线程 问题的一个特例是,从构造函数内启动了一个线程,由于当一个对象拥有一个线程时,通常这个线程要么是一个内部类,要么我们将         this 引用传递给其构造函数(或者该类本身继承了         Thread 类)。如果一个对象将拥有一个线程,那么,如果对象如         Thread 那样提供一个         start() 方法,并从         start() 方法而不是从构造函数启动线程,那是最好的。虽然通过接口,这会暴露类的一些实现细节(譬如,可能存在拥有一个线程),这往往是我们不期望的,但在这种情况下,从构造函数启动线程的害处要比隐藏实现所带来的好处多。      
“公布”是指什么?在构造期间,不是所有对         this 引用的引用都是有害的,只有那些公布引用,使其它线程看到该引用的引用才是有害的。确定与其它对象共享         this 引用是否安全,需要详细了解对象的可见性以及对象将如何利用引用。关于让         this 引用在构造期间逃脱,清单 5 列出了一些安全和不安全做法的示例:      
清单 5. 在构造期间,安全和不安全地使用“this”引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Safe {
  private Object me;
  private Set set = new HashSet();
  private Thread thread;
    public void run() {
    // Safe because "me" is not visible from any other thread
    me = this;
    // Safe because "set" is not visible from any other thread
    set.add(this);
    // Safe because MyThread won't start until construction is complete
    // and the constructor doesn't publish the reference
    thread = new MyThread(this);
  }
    public void run() {
    thread.start();
  }
  private class MyThread(Object o) {
    private Object theObject;
    public MyThread(Object o) {
      this.theObject = o;
    }
    ...
  }
}
public class Unsafe {
  public static Unsafe anInstance;
  public static Set set = new HashSet();
  private Set mySet = new HashSet();
    public void run() {
    // Unsafe because anInstance is globally visible
    anInstance = this;
    // Unsafe because SomeOtherClass.anInstance is globally visible
    SomeOtherClass.anInstance = this;
    // Unsafe because SomeOtherClass might save the "this" reference
    // where another thread could see it
    SomeOtherClass.registerObject(this);
    // Unsafe because set is globally visible
    set.add(this);
    // Unsafe because we are publishing a reference to mySet
    mySet.add(this);
    SomeOtherClass.someMethod(mySet);
    // Unsafe because the "this" object will be visible from the new
    // thread before the constructor completes
    thread = new MyThread(this);
    thread.start();
  }
    public void run() {
    // Unsafe because "c" may be visible from other threads
    c.add(this);
  }
}




正如您所见,在         Unsafe 类中许多不安全的构造与         Safe 类中安全的构造有很多相似之处。确定         this 引用对其它线程是否可见是一项很棘手的工作。最好的策略是,在构造函数中完全避免使用         this 引用(直接或间接)。然而,实际上这种完全避免使用 this 引用的可能并不总是存在。但只要记住,在构造函数中谨慎使用         this 引用和创建非静态内部类的实例。
返回列表