友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第91部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!




…………………………………………………………Page 529……………………………………………………………

    g2。list(); // (9)  

    // Add a bunch of new threads to g2:  

    for (int i = 0; i 《 5; i++)  

      new Thread(g2; Integer。toString(i));  

    // Show information about all threadgroups  

    // and threads:  

    sys。list(); // (10)  

    System。out。println(〃Starting all threads:〃);  

    Thread'' all = new Thread'sys。activeCount()';  

    sys。enumerate(all);  

    for(int i = 0; i 《 all。length; i++)  

      if(!all'i'。isAlive())  

        all'i'。start();  

    // Suspends & Stops all threads in   

    // this group and its subgroups:  

    System。out。println(〃All threads started〃);  

    sys。suspend(); // Deprecated in Java 1。2  

    // Never gets here。。。  

    System。out。println(〃All threads suspended〃);  

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

    System。out。println(〃All threads stopped〃);  

  }  

} ///:~  

  

下面的输出结果已进行了适当的编辑,以便用一页能够装下(java。lang。已被删去),而且添加了适当的数 

字,与前面程序列表中括号里的数字对应:  

  

(1) ThreadGroup'name=system;maxpri=10'  

      Thread'main;5;system'  

(2) ThreadGroup'name=system;maxpri=9'  

      Thread'main;6;system'  

(3) ThreadGroup'name=g1;maxpri=9'  

      Thread'A;9;g1'  

(4) ThreadGroup'name=g1;maxpri=8'  

      Thread'A;9;g 1'  

(5) ThreadGroup'name=g1;maxpri=8'  

      Thread'A;9;g1'  

      Thread'B;8;g1'  

(6) ThreadGroup'name=g1;maxpri=3'  

      Thread'A;9;g1'  

      Thread'B;8;g1'  

      Thread'C;6;g1'  

(7) ThreadGroup'name=g1;maxpri=3'  

      Thread'A;9;g1'  

      Thread'B;8;g1'  

      Thread'C;3;g1'  

(8) ThreadGroup'name=g2;maxpri=3'  

(9) ThreadGroup'name=g2;maxpri=3'  

(10)ThreadGroup'name=system;maxpri=9'  

      Thread'main;6;system'  

      ThreadGroup'name=g1;maxpri=3'  

        Thread'A;9;g1'  



                                                                                           528 


…………………………………………………………Page 530……………………………………………………………

        Thread'B;8;g1'  

        Thread'C;3;g1'  

        ThreadGroup'name=g2;maxpri=3'  

          Thread'0;6;g2'  

          Thread'1;6;g2'  

          Thread'2;6;g2'  

          Thread'3;6;g2'  

          Thread'4;6;g2'  

Starting all threads:  

All threads started  

  

所有程序都至少有一个线程在运行,而且 main()采取的第一项行动便是调用Thread 的一个static (静态) 

方法,名为 currentThread()。从这个线程开始,线程组将被创建,而且会为结果调用 list()。输出如下:  

  

(1) ThreadGroup'name=system;maxpri=10'  

      Thread'main;5;system'  

  

我们可以看到,主线程组的名字是 system,而主线程的名字是main ,而且它从属于system线程组。  

第二个练习显示出 system 组的最高优先级可以减少,而且main 线程可以增大自己的优先级:  

  

(2) ThreadGroup'name=system;maxpri=9'  

      Thread'main;6;system'  

  

第三个练习创建一个新的线程组,名为g1;它自动从属于system 线程组,因为并没有明确指定它的归属关 

系。我们在 g1 内部放置了一个新线程,名为A 。随后,我们试着将这个组的最大优先级设到最高的级别,并 

将A 的优先级也设到最高一级。结果如下:  

  

(3) ThreadGroup'name=g1;maxpri=9'  

      Thread'A;9;g1'  

  

可以看出,不可能将线程组的最大优先级设为高于它的父线程组。  

第四个练习将g1 的最大优先级降低两级,然后试着把它升至 Thread。MAX_PRIORITY。结果如下:  

  

(4) ThreadGroup'name=g1;maxpri=8'  

      Thread'A;9;g1'  

  

同样可以看出,提高最大优先级的企图是失败的。我们只能降低一个线程组的最大优先级,而不能提高它。 

此外,注意线程A 的优先级并未改变,而且它现在高于线程组的最大优先级。也就是说,线程组最大优先级 

的变化并不能对现有线程造成影响。  

第五个练习试着将一个新线程设为最大优先级。如下所示:  

  

(5) ThreadGroup'name=g1;maxpri=8'  

      Thread'A;9;g1'  

      Thread'B;8;g1'  

  

因此,新线程不能变到比最大线程组优先级还要高的一级。  

这个程序的默认线程优先级是 6;若新建一个线程,那就是它的默认优先级,而且不会发生变化,除非对优 

先级进行了特别的处理。练习六将把线程组的最大优先级降至默认线程优先级以下,看看在这种情况下新建 

一个线程会发生什么事情:  

  

(6) ThreadGroup'name=g1;maxpri=3'  

      Thread'A;9;g1'  



                                                                                          529 


…………………………………………………………Page 531……………………………………………………………

      Thread'B;8;g1'  

      Thread'C;6;g1'  

  

尽管线程组现在的最大优先级是3,但仍然用默认优先级 6 来创建新线程。所以,线程组的最大优先级不会 

影响默认优先级(事实上,似乎没有办法可以设置新线程的默认优先级)。  

改变了优先级后,接下来试试将其降低一级,结果如下:  

  

(7) ThreadGroup'name=g1;maxpri=3'  

      Thread'A;9;g1'  

      Thread'B;8;g1'  

      Thread'C;3;g1'  

  

因此,只有在试图改变优先级的时候,才会强迫遵守线程组最大优先级的限制。  

我们在 (8)和(9)中进行了类似的试验。在这里,我们创建了一个新的线程组,名为g2,将其作为g1 的一个 

子组,并改变了它的最大优先级。大家可以看到,g2 的优先级无论如何都不可能高于g1:  

  

(8) ThreadGroup'name=g2;maxpri=3'  

(9) ThreadGroup'name=g2;maxpri=3'  

  

也要注意在 g2 创建的时候,它会被自动设为 g1 的线程组最大优先级。  

经过所有这些实验以后,整个线程组和线程系统都会被打印出来,如下所示:  

  

(10)ThreadGroup'name=system;maxpri=9'  

      Thread'main;6;system'  

      ThreadGroup'name=g1;maxpri=3'  

        Thread'A;9;g1'  

        Thread'B;8;g1'  

        Thread'C;3;g1'  

        ThreadGroup'name=g2;maxpri=3'  

          Thread'0;6;g2'  

          Thread'1;6;g2'  

          Thread'2;6;g2'  

          Thread'3;6;g2'  

          Thread'4;6;g2'  

  

所以由线程组的规则所限,一个子组的最大优先级在任何时候都只能低于或等于它的父组的最大优先级。  

本程序的最后一个部分演示了用于整组线程的方法。程序首先遍历整个线程树,并启动每一个尚未启动的线 

程。例如,system组随后会被挂起(暂停),最后被中止(尽管用 suspend()和 stop()对整个线程组进行操 

作看起来似乎很有趣,但应注意这些方法在Java 1。2 里都是被“反对”的)。但在挂起 system 组的同时, 

也挂起了main 线程,而且整个程序都会关闭。所以永远不会达到让线程中止的那一步。实际上,假如真的中 

止了main 线程,它会“掷”出一个ThreadDeath 违例,所以我们通常不这样做。由于ThreadGroup 是从 

Object 继承的,其中包含了wait()方法,所以也能调用wait(秒数×1000),令程序暂停运行任意秒数的时 

间。当然,事前必须在一个同步块里取得对象锁。  

ThreadGroup 类也提供了 suspend()和 resume()方法,所以能中止和启动整个线程组和它的所有线程,也能 

中止和启动它的子组,所有这些只需一个命令即可(再次提醒,suspend()和 resume()都是Java 1。2 所“反 

对”的)。  

从表面看,线程组似乎有些让人摸不着头脑,但请注意我们很少需要直接使用它们。  



14。5 回顾 runnable  



在本章早些时候,我曾建议大家在将一个程序片或主Frame 当作Runnable 的实现形式之前,一定要好好地想 

一想。若采用那种方式,就只能在自己的程序中使用其中的一个线程。这便限制了灵活性,一旦需要用到属 

于那种类型的多个线程,就会遇到不必要的麻烦。  



                                                                                    530 


…………………………………………………………Page 532……………………………………………………………

当然,如果必须从一个类继承,而且想使类具有线程处理能力,则Runnable 是一种正确的方案。本章最后一 

个例子对这一点进行了剖析,制作了一个 RunnableCanvas 类,用于为自己描绘不同的颜色(Canvas 是“画 

布”的意思)。这个应用被设计成从命令行获得参数值,以决定颜色网格有多大,以及颜色发生变化之间的 

sleep()有多长。通过运用这些值,大家能体验到线程一些有趣而且可能令人费解的特性:  

  

//: ColorBoxes。java  

// Using the Runnable interface  

import java。awt。*;  

import java。awt。event。*;  

  

class CBox extends Canvas implements Runnable {  

  private Thread t;  

  private int pause;  

  private static final Color'' colors = {   

    Color。black; Color。blue; Color。cyan;   

    Color。darkGray; Color。gray; Color。green;  

    Color。lightGray; Color。magenta;   

    Color。orange; Color。pink; Color。red;   

    Color。white; Color。yellow   

  };  

  private Color cColor = newColor();  

  private static final Color newColor() {  

    return colors'  

      (int)(Math。random() * colors。length)  

    ';  

  }  

  public void paint(Graphics  g) {  

    g。setColor(cColor);  

    Dimension s = getSize();  

    g。fillRect(0; 0; s。width; s。height);  

  }  

  public CBox(int pause) {  

    this。pause = pause;  

    t = new Thread(this);  

    t。start();   

  }  

  public void run() {  

    while(true) {  

      cColor = newColor();  

      repaint();  

      try {  

        t。sleep(pause);  

      } catch(InterruptedException e) {}  

    }   

  }  

}   

  

public class ColorBoxes extends Frame {  

  public ColorBoxes(int pause; int grid) {  

    setTitle(〃ColorBoxes〃);  

    setLayout(new GridLayout(grid; grid));  

    for (int i = 0; i 《 grid * grid; i++)  



                                                                                               531 


…………………………………………………………Page 533……………………………………………………………

      add(new CBox(pause));  

    addWindowListener(new WindowAdapter() {  

      public void windowClosing(WindowEvent e) {  

        System。exit(0);  

      }  

    });  

  }     

  public static void main(String'' args) {  

    int pause = 50;  

    int grid = 8;  

    if(args。length 》 0)   

      pause = Integer。parseInt(args'0');  

    if(args。length 》 1)  

      grid = Integer。parseInt(args'1');  

    Frame f = new ColorBoxes(pause; grid);  

    f。setSize(500; 400);  

    f。setVisible(true);    

  }  

} ///:~  

  

ColorBoxes 是一个典型的应用(程序),有一个构建器用于设置 GUI。这个构建器采用 int grid 的一个参 

数,用它设置GridLayout (网格布局),使每一维里都有一个grid 单元。随后,它添加适当数量的 CBox 对 

象,用它们填充网格,并为每一个都传递pause 值。在 main()中,我们可看到如何对pause 和 grid 的默认 

值进行修改(如果用命令行参数传递)。  

CBox 是进行正式工作的地方。它是从Canvas 继承的,并实现了Runnable 接口,使每个 Canvas 也能是一个 

Thread。记住在实现Runnable 的时候,并没有实际产生一个 Thread 对象,只是一个拥有 run()方法的类。 

因此,我们必须明确地创建一个Thread 对象,并将 Runnable 对象传递给构建器,随后调用 start() (在构 

建器里进行)。在 CBox 里,这个线程的名字叫作 t。  

请留意数组 colors,它对 Color 类中的所有颜色进行了列举(枚举)。它在newColor()中用于产生一种随机 

选择的颜色。当前的单元(格)颜色是cColor。  

paint()则相当简单——只是将颜色设为cColor,然后用那种颜色填充整张画布(Canvas )。  

在run()中,我们看到一个无限循环,它将 cColor 设为一种随机颜色,然后调用 repaint()把它显示出来。 

随后,对线程执行 sleep(),使其“休眠”由命令行指定的时间长度。  

由于这种设计方案非常灵活,而且线程处理同每个Canvas 元素都紧密结合在一起,所以在理论上可以生成任 

意多的线程(但在实际应用中,这要受到JVM 能够从容对付的线程数量的限制)。  

这个程序也为我们提供了一个有趣的评测基准,因为它揭示了不同JVM 机制在速度上造成的戏剧性的差异。  



14。5。1 过多的线程  



有些时候,我们会发现ColorBoxes 几乎陷于停顿状态。在我自己的机器上,这一情况在产生了 10×10 的网 

格之后发生了。为什么会这样呢?自然地,我们有理由怀疑AWT 对它做了什么事情。所以这里有一个例子能 

够测试那个猜测,它产生了较少的线程。代码经过了重新组织,使一个Vector 实现了Runnable ,而且那个 

Vector 容纳了数量众多的色块,并随机挑选一些进行更新。随后,我们创建大量这些Vector 对象,数量大 

致取决于我们挑选的网格维数。结果便是我们得到比色块少得多的线程。所以假如有一个速度的加快,我们 

就能立即知道,因为前例的线程数量太多了。如下所示:  

  

//: ColorBoxes2。java  

// Balancing thread use  

import java。awt。*;  

import java。awt。event。*;  

import java。util。*;  

  

class CBox2 extends Canvas {  



                                                                                       532 


…………………………………………………………Page 534……………………………………………………………

  private static final Color'' colors = {   

    Color。black; Color。blue; Color。cyan;   

    Color。darkGray; Color。gray; Color。green;  

    Color。lightGray; Color。magenta;   

    Color。orange; Color。pink; Color。red;   

    Color。white; Color。yellow   

  };  

  private Color cColor = newColor();  

  private static final Color newColor() {  

    return colors'  

      (int)(Math。random() * colors。length)  

    ';  

  }  

  void nextColor() {  

    cColor = newColor();  

    repaint();  

  }  

  public void paint(Graphics  g) {  

    g。setColor(cColor);  

    Dimension s = getSize();  

    g。fillRect(0; 0; s。width; s。height);  

  }  

}  

  

class CBoxVector   

  extends Vector implements Runnable {  

  private Thread t;  

  private int pause;  

  public CBoxVector(int pause) {  

    this。pause = pause;  

    t = new Thread(this);  

  }  

  public void go() { t。start(); }  

  public void run() {  

    while(true) {  

      int i = (int)(Math。random() * size());  

      ((CBox2)elementAt(i))。nextColor();  

      try {  

        t。sleep(pause);  

      } catch(InterruptedException e) {}  

    }   

  }  

}  

  

public class ColorBoxes2 extends Frame {  

  private CBoxVector'' v;  

  public ColorBoxes2(int pause; int grid) {  

    setTitle(〃ColorBoxes2〃);  

    setLayout(new GridLayout(grid; grid));  

    v = new CBoxVector'grid';  

    for(int i = 0; i 《 grid; i++)  

      v'i' = new CBoxVector(pause);  



                                                                                             533 


…………………………………………………………Page 535……………………………………………………………

    for (int i = 0; i 《 grid * grid; i++) {  

      v'i % grid'。addElement(new CBox2());  

      add((CBox2)v'i % grid'。lastElement());  

    }  

    for(int i = 0; i 《 grid; i++)  

      v'i'。go();  

    addWindowListener(new WindowAdapter() {  

      public void windowClosing(WindowEvent e) {  

        System。exit(0);  

      }  

    });  

  }     

  public static void main(String'' args) {  

    // Shorter default pause than ColorBoxes:  

    int pause = 5;  

    int grid = 8;  

    if(args。length 》 0)   

      pause = Integer。parseInt(args'0');  

    if(args。length 》 1)  

      grid = Integer。parseInt(args'1');  

    Frame f = new ColorBoxes2(pause; grid);  

    f。setSize(500; 400);  

    f。setVisible(true);    

  }  

} ///:~  

  

在ColorBoxes2 中,我们创建了CBoxVector 的一个数组,并对其初始化,使其容下各个CBoxVector 网格。 

每个网格都知道自己该“睡眠”多长的时间。随后为每个 CBoxVector 都添加等量的 Cbox2 对象,而且将每个 

Vector 都告诉给 go(),用它来启动自己的线程。  

CBox2 类似CBox——能用一种随机选择的颜色描绘自己。但那就是 CBox2 能够做的全部工作。所有涉及线程 

的处理都已移至CBoxVector 进行。  

CBoxVector 也可以拥有继承的 Thread,并有一个类型为Vector 的成员对象。这样设计的好处就是 

addElement()和 elementAt()方法可以获得特定的参数以及返回值类型,而不是只能获得常规 Object (它们 

的名字也可以变得更短)。然而,这里采用的设计表面上看需要较少的代码。除此以外,它会自动保留一个 

Vector 的其他所有行为。由于 elementAt()需要大量进行“封闭”工作,用到许多括号,所以随着代码主体 

的扩充,最终仍有
返回目录 上一页 下一页 回到顶部 10 9
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!