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

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

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




    return text;   

  }  

  public synchronized void   

  setBangText(String newText) {  

    text = newText;  

  }  

  public synchronized int getFontSize() {   

    return fontSize;   

  }  

  public synchronized void   

  setFontSize(int newSize) {  



                                                                                          507 


…………………………………………………………Page 509……………………………………………………………

    fontSize = newSize;  

  }  

  public synchronized Color getTextColor() {  

    return tColor;   

  }  

  public synchronized void   

  setTextColor(Color newColor) {  

    tColor = newColor;  

  }  

  public void paint(Graphics g) {  

    g。setColor(Color。black);  

    g。drawOval(xm cSize/2; ym cSize/2;   

      cSize; cSize);  

  }  

  // This is a multicast listener; which is  

  // more typically used than the unicast  

  // approach taken in BangBean。java:  

  public synchronized void addActionListener (  

      ActionListener l) {  

    actionListeners。addElement(l);  

  }  

  public synchronized void removeActionListener(  

      ActionListener l) {  

    actionListeners。removeElement(l);  

  }  

  // Notice this isn't synchronized:  

  public void notifyListeners() {  

    ActionEvent a =  

      new ActionEvent(BangBean2。this;  

        ActionEvent。ACTION_PERFORMED; null);  

    Vector lv = null;  

    // Make a copy of the vector in case someone  

    // adds a listener while we're   

    // calling listeners:  

    synchronized(this) {  

      lv = (Vector)actionListeners。clone();  

    }  

    // Call all the listener methods:  

    for(int i = 0; i 《 lv。size(); i++) {  

      ActionListener al =   

        (ActionListener)lv。elementAt(i);  

      al。actionPerformed(a);  

    }  

  }  

  class ML extends MouseAdapter {  

    public void mousePressed(MouseEvent e) {  

      Graphics g = getGraphics();  

      g。setColor(tColor);  

      g。setFont(  

        new Font(  

          〃TimesRoman〃; Font。BOLD; fontSize));  

      int width =   



                                                                                        508 


…………………………………………………………Page 510……………………………………………………………

        g。getFontMetrics()。stringWidth(text);  

      g。drawString(text;   

        (getSize()。width width) /2;  

        getSize()。height/2);  

      g。dispose();  

      notifyListeners();  

    }  

  }  

  class MM extends MouseMotionAdapter {  

    public void mouseMoved(MouseEvent e) {  

      xm = e。getX();  

      ym = e。getY();  

      repaint();  

    }  

  }  

  // Testing the BangBean2:  

  public static void main(String'' args) {  

    BangBean2 bb = new BangBean2();  

    bb。addActionListener(new ActionListener() {  

      public void actionPerformed(ActionEvent e){  

        System。out。println(〃ActionEvent〃 + e);  

      }  

    });  

    bb。addActionListener(new ActionListener() {  

      public void actionPerformed(ActionEvent e){  

        System。out。println(〃BangBean2 action〃);  

      }  

    });  

    bb。addActionListener(new ActionListener() {  

      public void actionPerformed(ActionEvent e){  

        System。out。println(〃More action〃);  

      }  

    });  

    Frame aFrame = new Frame(〃BangBean2 Test〃);  

    aFrame。addWindowListener(new WindowAdapter(){  

      public void windowClosing(WindowEvent e) {  

        System。exit(0);  

      }  

    });  

    aFrame。add(bb; BorderLayout。CENTER);  

    aFrame。setSize(300;300);  

    aFrame。setVisible(true);  

  }  

} ///:~  

  

很容易就可以为方法添加synchronized。但注意在addActionListener()和 removeActionListener()中,现 

在添加了ActionListener,并从一个 Vector 中移去,所以能够根据自己愿望使用任意多个。  

我们注意到,notifyListeners()方法并未设为“同步”。可从多个线程中发出对这个方法的调用。另外,在 

对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。  



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