Java线程模型缺陷研究
如果读和写线程都在等待,缺省情况下,读线程会首先进行。但是,可以使用$writer_priority 属性修改类的定义来改变这种缺省方式。
访问部分创建的对象应是非法的
当前情况下,JLS 允许访问部分创建的对象。例如,在一个构造函数中创建的线程可以访问正被创建的对象,既使此对象没有完全被创建。
设置x 为 -1 的线程可以和设置 x 为 0 的线程同时进行。所以,此时 x 的值无法预测。
对此问题的一个解决方法是,在构造函数没有返回之前,对于在此构造函数中创建的线程,既使它的优先级比调用new 的线程高,也要禁止运行它的 run() 方法。
这就是说,在构造函数返回之前,start() 请求必须被推迟。
另外,Java 编程语言应可允许构造函数的同步。换句话说,下面的代码(在当前情况下是非法的)会象预期的那样工作:
我认为第一种方法比第二种更简洁,但实现起来更为困难。
volatile关键字应象预期的那样工作
JLS 要求保留对于 volatile 操作的请求。大多数 Java 虚拟机都简单地忽略了这部分内容,这是不应该的。在多处理器的情况下,许多主机都出现了这种问题,但是它本应由 JLS 加以解决的。如果您对这方面感兴趣,马里兰大学的 Bill Pugh 正在致力于这项工作(请参阅参考资料 )。
访问的问题
如果缺少良好的访问控制,会使线程编程非常困难。大多数情况下,如果能保证线程只从同步子系统中调用,不必考虑线程安全(threadsafe)问题。我建议对 Java 编程语言的访问权限概念做如下限制;应精确使用 package 关键字来限制包访问权。我认为当缺省行为的存在是任何一种计算机语言的一个瑕疵,我对现在存在这种缺省权限感到很迷惑(而且这种缺省是“包(package)”级别的而不是“私有(private)”)。在其它方面,Java 编程语言都不提供等同的缺省关键字。虽然使用显式的 package 的限定词会破坏现有代码,但是它将使代码的可读性更强,并能消除整个类的潜在错误 (例如,如果访问权是由于错误被忽略,而不是被故意忽略)。 重新引入 private protected ,它的功能应和现在的 protected 一样,但是不应允许包级别的访问。 允许 private private 语法指定“实现的访问”对于所有外部对象是私有的,甚至是当前对象是的同一个类的。对于“.”左边的唯一引用(隐式或显式)应是 this 。 扩展 public 的语法,以授权它可制定特定类的访问。例如,下面的代码应允许 Fred 类的对象可调用 some_method() ,但是对其它类的对象,这个方法应是私有的。
这种建议不同于 C++ 的 "friend" 机制。 在 "friend" 机制中,它授权一个类访问另一个类的所有 私有部分。在这里,我建议对有限的方法集合进行严格控制的访问。用这种方法,一个类可以为另一个类定义一个接口,而这个接口对系统的其余类是不可见的。
除非域引用的是真正不变(immutable)的对象或static final 基本类型,否则所有域的定义应是 private 。对于一个类中域的直接访问违反了 OO 设计的两个基本规则:抽象和封装。从线程的观点来看,允许直接访问域只使对它进行非同步访问更容易一些。
增加$property 关键字。带有此关键字的对象可被一个“bean 盒”应用程序访问,这个程序使用在 Class 类中定义的反射操作(introspection) API,否则与 private private 同效。 $property 属性可用在域和方法,这样现有的 JavaBean getter/setter 方法可以很容易地被定义为属性。
不变性(immutability)
由于对不变对象的访问不需要同步,所以在多线程条件下,不变的概念(一个对象的值在创建后不可更改)是无价的。Java 编程言语中,对于不变性的实现不够严格,有两个原因:对于一个不变对象,在其被未完全创建之前,可以对它进行访问。这种访问对于某些域可以产生不正确的值。 对于恒定 (类的所有域都是 final) 的定义太松散。对于由 final 引用指定的对象,虽然引用本身不能改变,但是对象本身可以改变状态。