技术开发 频道

Java线程模型缺陷研究

    在这个例子中,有很多明显的办法来解决问题:例如,对任何的方法都使用同步。但是在真实世界中,解决方法通常不是这么简单。

    一个可行的方法是,在wait() 中按照反顺序释放当前线程获取的 所有 锁,然后当等待条件满足后,重新按原始获取顺序取得它们。但是,我能想象出利用这种方式的代码对于人们来说简直无法理解,所以我认为它不是一个真正可行的方法。如果您有好的方法,请给我发 e-mail。

    我也希望能等到下述复杂条件被实现的一天。 

    其中a 、 b 和 c 是任意对象。

    修改Thread 类

    同时支持抢占式和协作式线程的能力在某些服务器应用程序中是基本要求,尤其是在想使系统达到最高性能的情况下。我认为 Java 编程语言在简化线程模型上走得太远了,并且 Java 编程语言应支持 Posix/Solaris 的“绿色(green)线程”和“轻便(lightweight)进程”概念(在“(Taming Java Threads ”第一章中讨论)。 这就是说,有些 Java 虚拟机的实现(例如在 NT 上的 Java 虚拟机)应在其内部仿真协作式进程,其它 Java 虚拟机应仿真抢占式线程。而且向 Java 虚拟机加入这些扩展是很容易的。

    一个 Java 的Thread 应始终是抢占式的。这就是说,一个 Java 编程语言的线程应像 Solaris 的轻便进程一样工作。 Runnable 接口可以用于定义一个 Solaris 式的“绿色线程”,此线程必需能把控制权转给运行在相同轻便进程中的其它绿色线程。

    能有效地为Runnable 对象产生一个绿色线程,并把它绑定到由 Thread 对象代表的轻便进程中。这种实现对于现有代码是透明的,因为它的有效性和现有的完全一样。

    把Runnable 对象想成为绿色线程,使用这种方法,只需向 Thread 的构造函数传递几个 Runnable 对象,就可以扩展 Java 编程语言的现有语法,以支持在一个单一轻便线程有多个绿色线程。(绿色线程之间可以相互协作,但是它们可被运行在其它轻便进程 ( Thread 对象) 上的绿色进程( Runnable 对象) 抢占。)。例如,下面的代码会为每个 runnable 对象创建一个绿色线程,这些绿色线程会共享由 Thread 对象代表的轻便进程。

    现有的覆盖(override)Thread 对象并实现 run() 的习惯继续有效,但是它应映射到一个被绑定到一轻便进程的绿色线程。(在 Thread() 类中的缺省 run() 方法会在内部有效地创建第二个 Runnable 对象。)

    线程间的协作

    应在语言中加入更多的功能以支持线程间的相互通信。目前,PipedInputStream 和 PipedOutputStream 类可用于这个目的。但是对于大多数应用程序,它们太弱了。我建议向 Thread 类加入下列函数: 增加一个 wait_for_start() 方法,它通常处于阻塞状态,直到一个线程的 run() 方法启动。(如果等待的线程在调用 run 之前被释放,这没有什么问题)。用这种方法,一个线程可以创建一个或多个辅助线程,并保证在创建线程继续执行操作之前,这些辅助线程会处于运行状态。 (向 Object 类)增加 $send (Object o) 和 Object=$receive() 方法,它们将使用一个内部阻断队列在线程之间传送对象。阻断队列应作为第一个 $send() 调用的副产品被自动创建。 $send() 调用会把对象加入队列。 $receive() 调用通常处于阻塞状态,直到有一个对象被加入队列,然后它返回此对象。这种方法中的变量应支持设定入队和出队的操作超时能力: $send (Object o, long timeout) 和 $receive (long timeout)。

   对于读写锁的内部支持

    读写锁的概念应内置到 Java 编程语言中。读写器锁在“Taming Java Threads ”(和其它地方)中有详细讨论,概括地说:一个读写锁支持多个线程同时访问一个对象,但是在同一时刻只有一个线程可以修改此对象,并且在访问进行时不能修改。

    对于一个对象,应该只有在$writing 块中没有线程时,才支持多个线程进入 $reading 块。在进行读操作时,一个试图进入 $writing 块的线程会被阻断,直到读线程退出 $reading 块。 当有其它线程处于 $writing 块时,试图进入 $reading 或 $writing 块的线程会被阻断,直到此写线程退出 $writing 块。
0
相关文章