锁和条件是线程同步的强大工具,但他们不是严格意义上的面相对象。很多年来,研究人员一直在寻找一种方法,可以在不需要程序员考虑具体如何加锁的情况下保证多线程的安全。其中最成功的解决方案就是监视器的概念,最先由Per Brinch Hansen 和Tony Hoare 在20世纪70年代提出的。在Java中,一个监视器由一下这些特征:
- 一个监视器是只有一个私有域的类。
- 每个监视器类的对象都有一个相关的锁。
- 这个锁负责所有方法加载。换句话说,如果客户端调用obj.method(),那么在方法调用开始时将自动获取对象obj的锁,在方法返回时释放。因为所有域都是私有的,这种安排保证在一个线程对对象进行操作时其他线程不能访问该域。
- 这个锁可有任意多个关联条件。
Java的设计者并不十分精确地才用了监视器的概念。Java中的每个对象都有一个一个隐式的锁和一个隐式的条件。如果一个方法有synchronized关键字来修饰,它就表现的像一个监视器的方法,通过调用wait/notify/notifyAll来访问条件变量。
但是,Java对象毕竟与监视器不同,其中有两点使安全性下降了:
- 域不要求必须是private。
- 方法不要求必须是synchronized。
但是这种对安全的漠视激怒了Per Brinch Hansen,他在一次对原始Java中多线程的严厉评论中写道:”令人震惊的是,在
监视器和并行Pascal出现四分之一个世纪后,Java的这种不安全的并行机制依然被编程社区所接受,这毫无益处。“
[Java's Insecure Parallelism,ACM SIGPLAN Notices 34:38~45,April 1999]