友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
狗狗书籍 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第219章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




对notifyListeners()调用的中途,也可能发出对addActionListener()和 removeActionListener() 的调 

用。这显然会造成问题,因为它否定了Vector actionListeners 。为缓解这个问题,我们在一个 

synchronized从句中“克隆”了 Vector,并对克隆进行了否定。这样便可在不影响notifyListeners()的前 

提下,对Vector 进行操纵。  



                                                                                          509 


…………………………………………………………Page 511……………………………………………………………

paint()方法也没有设为“同步”。与单纯地添加自己的方法相比,决定是否对过载的方法进行同步要困难得 

多。在这个例子中,无论paint()是否“同步”,它似乎都能正常地工作。但必须考虑的问题包括:  

(1) 方法会在对象内部修改“关键”变量的状态吗?为判断一个变量是否“关键”,必须知道它是否会被程 

序中的其他线程读取或设置(就目前的情况看,读取或设置几乎肯定是通过“同步”方法进行的,所以可以 

只对它们进行检查)。对paint()的情况来说,不会发生任何修改。  

(2) 方法要以这些“关键”变量的状态为基础吗?如果一个“同步”方法修改了一个变量,而我们的方法要 

用到这个变量,那么一般都愿意把自己的方法也设为“同步”。基于这一前提,大家可观察到cSize 由“同 

步”方法进行了修改,所以paint()应当是“同步”的。但在这里,我们可以问:“假如 cSize 在paint()执 

行期间发生了变化,会发生的最糟糕的事情是什么呢?”如果发现情况不算太坏,而且仅仅是暂时的效果, 

那么最好保持paint()的“不同步”状态,以避免同步方法调用带来的额外开销。  

(3) 要留意的第三条线索是 paint()基础类版本是否“同步”,在这里它不是同步的。这并不是一个非常严 

格的参数,仅仅是一条“线索”。比如在目前的情况下,通过同步方法(好cSize)改变的一个字段已合成 

到paint()公式里,而且可能已改变了情况。但请注意,synchronized不能继承——也就是说,假如一个方 

法在基础类中是“同步”的,那么在衍生类过载版本中,它不会自动进入“同步”状态。  

TestBangBean2 中的测试代码已在前一章的基础上进行了修改,已在其中加入了额外的“听众”,从而演示 

了BangBean2 的多造型能力。  



14。3 堵塞  



一个线程可以有四种状态:  

(1) 新(New):线程对象已经创建,但尚未启动,所以不可运行。  

(2) 可运行(Runnable ):意味着一旦时间分片机制有空闲的CPU 周期提供给一个线程,那个线程便可立即 

开始运行。因此,线程可能在、也可能不在运行当中,但一旦条件许可,没有什么能阻止它的运行——它既 

没有“死”掉,也未被“堵塞”。  

(3) 死(Dead ):从自己的run()方法中返回后,一个线程便已“死”掉。亦可调用 stop()令其死掉,但会 

产生一个违例——属于Error 的一个子类(也就是说,我们通常不捕获它)。记住一个违例的“掷”出应当 

是一个特殊事件,而不是正常程序运行的一部分。所以不建议你使用 stop() (在Java 1。2 则是坚决反 

对)。另外还有一个destroy()方法(它永远不会实现),应该尽可能地避免调用它,因为它非常武断,根 

本不会解除对象的锁定。  

(4) 堵塞(Blocked):线程可以运行,但有某种东西阻碍了它。若线程处于堵塞状态,调度机制可以简单地 

跳过它,不给它分配任何CPU 时间。除非线程再次进入“可运行”状态,否则不会采取任何操作。  



14。3。1 为何会堵塞  



堵塞状态是前述四种状态中最有趣的,值得我们作进一步的探讨。线程被堵塞可能是由下述五方面的原因造 

成的:  

(1) 调用 sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。  

(2) 用 suspend()暂停了线程的执行。除非线程收到 resume()消息,否则不会返回“可运行”状态。  

(3) 用wait()暂停了线程的执行。除非线程收到 nofify()或者notifyAll()消息,否则不会变成“可运行” 

 (是的,这看起来同原因2 非常相象,但有一个明显的区别是我们马上要揭示的)。  

(4) 线程正在等候一些 IO (输入输出)操作完成。  

(5) 线程试图调用另一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。  

  

亦可调用yield() (Thread 类的一个方法)自动放弃CPU,以便其他线程能够运行。然而,假如调度机制觉 

得我们的线程已拥有足够的时间,并跳转到另一个线程,就会发生同样的事情。也就是说,没有什么能防止 

调度机制重新启动我们的线程。线程被堵塞后,便有一些原因造成它不能继续运行。  

下面这个例子展示了进入堵塞状态的全部五种途径。它们全都存在于名为 Blocking。java 的一个文件中,但 

在这儿采用散落的片断进行解释(大家可注意到片断前后的“Continued”以及“Continuing”标志。利用第 

17章介绍的工具,可将这些片断连结到一起)。首先让我们看看基本的框架:  

  

//: Blocking。java  

// Demonstrates the various ways a thread  

// can be blocked。  



                                                                   510 


…………………………………………………………Page 512……………………………………………………………

import java。awt。*;  

import java。awt。event。*;  

import java。applet。*;  

import java。io。*;  

  

//////////// The basic framework ///////////  

class Blockable extends Thread {  

  private Peeker peeker;  

  protected TextField state = new TextField(40);  

  protected int i;  

  public Blockable(Container c) {  

    c。add(state);  

    peeker = new Peeker(this; c);  

  }  

  public synchronized int read() { return i; }  

  protected synchronized void update() {  

    state。setText(getClass()。getName()  

      + 〃 state: i = 〃 + i);  

  }  

  public void stopPeeker() {   

    // peeker。stop(); Deprecated in Java 1。2  

    peeker。terminate(); // The preferred approach  

  }  

}  

  

class Peeker extends Thread {  

  private Blockable b;  

  private int session;  

  private TextField status = new TextFie ld(40);  

  private boolean stop = false;  

  public Peeker(Blockable b; Container c) {  

    c。add(status);  

    this。b = b;  

    start();  

  }  

  public void terminate() { stop = true; }  

  public void run() {  

    while (!stop) {  

      status。setText(b。getClass()。getName()  

        + 〃 Peeker 〃 + (++session)  

        + 〃; value = 〃 + b。read());  

       try {  

        sleep(100);  

      } catch (InterruptedException e){}  

    }  

  }  

} ///:Continued  

  

Blockable 类打算成为本例所有类的一个基础类。一个Blockable 对象包含了一个名为 state 的TextField 

 (文本字段),用于显示出对象有关的信息。用于显示这些信息的方法叫作update() 。我们发现它用 

getClass。getName()来产生类名,而不是仅仅把它打印出来;这是由于 update(0 不知道自己为其调用的那个 

类的准确名字,因为那个类是从Blockable 衍生出来的。  



                                                                                             511 


…………………………………………………………Pag
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!