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

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

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



Thread 的 destroy()方法根本没有实现;它类似一个根本不能恢复的suspend(),所以会发生与suspend()一 

样的死锁问题。然而,这一方法没有得到明确的“反对”,也许会在 Java 以后的版本(1。2版以后)实现, 

用于一些可以承受死锁危险的特殊场合。  

大家可能会奇怪当初为什么要实现这些现在又被“反对”的方法。之所以会出现这种情况,大概是由于 Sun 

公司主要让技术人员来决定对语言的改动,而不是那些市场销售人员。通常,技术人员比搞销售的更能理解 

语言的实质。当初犯下了错误以后,也能较为理智地正视它们。这意味着 Java 能够继续进步,即便这使 

Java 程序员多少感到有些不便。就我自己来说,宁愿面对这些不便之处,也不愿看到语言停滞不前。  



14。4 优先级  



线程的优先级(Priority )告诉调试程序该线程的重要程度有多大。如果有大量线程都被堵塞,都在等候运 

行,调试程序会首先运行具有最高优先级的那个线程。然而,这并不表示优先级较低的线程不会运行(换言 

之,不会因为存在优先级而导致死锁)。若线程的优先级较低,只不过表示它被准许运行的机会小一些而 

已。  

可用getPriority()方法读取一个线程的优先级,并用 setPriority()改变它。在下面这个程序片中,大家会 

发现计数器的计数速度慢了下来,因为它们关联的线程分配了较低的优先级:  

  

//: Counter5。java  

// Adjusting the priorities of threads  

import java。awt。*;  

import java。awt。event。*;  



                                                                                        521 


…………………………………………………………Page 523……………………………………………………………

import java。applet。*;  

  

class Ticker2 extends Thread {  

  private Button   

    b = new Button(〃Toggle〃);  

    incPriority = new Button(〃up〃);  

    decPriority = new Button(〃down〃);  

  private TextField   

    t = new TextField(10);  

    pr = new TextField(3); // Display priority  

  private int count = 0;  

  private boolean runFlag = true;  

  public Ticker2(Container c) {  

    b。addActionListener(new ToggleL());  

    incPriority。addActionListener(new UpL());  

    decPriority。addActionListener(new DownL());  

    Panel p = new Panel();  

    p。add(t);  

    p。add(pr);  

    p。add(b);  

    p。add(incPriority);  

    p。add(decPriority);  

    c。add(p);  

  }  

  class ToggleL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      runFlag = !runFlag;  

    }  

  }  

  class UpL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      int newPriority = getPriority() + 1;  

      if(newPriority 》 Thread。MAX_PRIORITY)  

        newPriority = Thread。MAX_PRIORITY;  

      setPriority(newPriority);  

    }  

  }  

  class DownL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      int newPriority = getPriority() 1;  

      if(newPriority 《 Thread。MIN_PRIORITY)  

        newPriority = Thread。MIN_PRIORITY;  

      setPriority(newPriority);  

    }  

  }  

  public void run() {  

    while (true) {  

      if(runFlag) {  

        t。setText(Integer。toString(count++));  

        pr。setText(  

          Integer。toString(getPriority()));  

      }  



                                                                                          522 


…………………………………………………………Page 524……………………………………………………………

      yield();  

    }  

  }  

}  

  

public class Counter5 extends Applet {  

  private Button   

    start = new Button(〃Start〃);  

    upMax = new Button(〃Inc Max Priority〃);  

    downMax = new Button(〃Dec Max Priority〃);  

  private boolean started = fal se;  

  private static final int SIZE = 10;  

  private Ticker2'' s = new Ticker2'SIZE';  

  private TextField mp = new TextField(3);  

  public void init() {  

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

      s'i' = new Ticker2(this);  

    add(new Label(〃MAX_PRIORITY = 〃  

      + Thread。MAX_PRIORITY));  

    add(new Label(〃MIN_PRIORITY = 〃  

      + Thread。MIN_PRIORITY));  

    add(new Label(〃Group Max Priority = 〃));  

    add(mp);   

    add(start);  

    add(upMax); add(downMax);  

    start。addActionListener(new StartL());  

    upMax。addActionListener(new UpMaxL());  

    downMax。addActionListener(new DownMaxL());  

    showMaxPriority();  

    // Recursively display parent thread groups:  

    ThreadGroup parent =   

      s'0'。getThreadGroup()。getParent();  

    while(parent != null) {  

      add(new Label(  

        〃Parent threadgroup max priority = 〃  

        + parent。getMaxPriority()));  

      parent = parent。getParent();  

    }  

  }  

  public void showMaxPriority() {  

    mp。setText(Integer。toString(  

      s'0'。getThreadGroup()。getMaxPriority()));  

  }  

  class StartL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      if(!started) {  

        started = true;  

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

          s'i'。start();  

      }  

    }  

  }  



                                                                                             523 


…………………………………………………………Page 525……………………………………………………………

  class UpMaxL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      int maxp =   

        s'0'。getThreadGroup()。getMaxPriority();  

      if(++maxp 》 Thread。MAX_PRIORITY)  

        maxp = Thread。MAX_PRIORITY;  

      s'0'。getThreadGroup()。setMaxPriority(maxp);  

      showMaxPriority();  

    }  

  }  

  class DownMaxL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      int maxp =   

        s'0'。getThreadGroup()。getMaxPriority();  

      if(……maxp 《 Thread。MIN_PRIORITY)  

        maxp = Thread。MIN_PRIORITY;  

      s'0'。getThreadGroup()。setMaxPriority(maxp);  

      showMaxPriority();  

    }  

  }  

  public static void main(String'' args) {  

    Counter5 applet = new Counter5();  

    Frame aFrame = new Frame(〃Counter5〃);  

    aFrame。addWindowListener(  

      new WindowAdapter() {  

        public void windowClosing(WindowEvent e) {  

          System。exit(0);  

        }  

      });  

    aFrame。add(applet; BorderLayout。CENTER);  

    aFrame。setSize(300; 600);  

    applet。init();  

    applet。start();  

    aFrame。setVisible(true);  

  }  

} ///:~  

  

Ticker 采用本章前面构造好的形式,但有一个额外的 TextField (文本字段),用于显示线程的优先级;以 

及两个额外的按钮,用于人为提高及降低优先级。  

也要注意yield()的用法,它将控制权自动返回给调试程序(机制)。若不进行这样的处理,多线程机制仍 

会工作,但我们会发现它的运行速度慢了下来(试试删去对yield()的调用)。亦可调用sleep(),但假若那 

样做,计数频率就会改由 sleep()的持续时间控制,而不是优先级。  

Counter5 中的init()创建了由 10个 Ticker2 构成的一个数组;它们的按钮以及输入字段(文本字段)由 

Ticker2 构建器置入窗体。Counter5 增加了新的按钮,用于启动一切,以及用于提高和降低线程组的最大优 

先级。除此以外,还有一些标签用于显示一个线程可以采用的最大及最小优先级;以及一个特殊的文本字 

段,用于显示线程组的最大优先级(在下一节里,我们将全面讨论线程组的问题)。最后,父线程组的优先 

级也作为标签显示出来。  

按下“up”(上)或“down”(下)按钮的时候,会先取得Ticker2 当前的优先级,然后相应地提高或者降 

低。  

运行该程序时,我们可注意到几件事情。首先,线程组的默认优先级是5。即使在启动线程之前(或者在创 

建线程之前,这要求对代码进行适当的修改)将最大优先级降到5 以下,每个线程都会有一个5 的默认优先 

级。  



                                                                                          524 


…………………………………………………………Page 526……………………………………………………………

最简单的测试是获取一个计数器,将它的优先级降低至 1,此时应观察到它的计数频率显著放慢。现在试着 

再次提高优先级,可以升高回线程组的优先级,但不能再高了。现在将线程组的优先级降低两次。线程的优 

先级不会改变,但假若试图提高或者降低它,就会发现这个优先级自动变成线程组的优先级。此外,新线程 

仍然具有一个默认优先级,即使它比组的优先级还要高(换句话说,不要指望利用组优先级来防止新线程拥 

有比现有的更高的优先级)。  

最后,试着提高组的最大优先级。可以发现,这样做是没有效果的。我们只能减少线程组的最大优先级,而 

不能增大它。  



14。4。1 线程组  



所有线程都隶属于一个线程组。那可以是一个默认线程组,亦可是一个创建线程时明确指定的组。在创建之 

初,线程被限制到一个组里,而且不能改变到一个不同的组。每个应用都至少有一个线程从属于系统线程 

组。若创建多个线程而不指定一个组,它们就会自动归属于系统线程组。  

线程组也必须从属于其他线程组。必须在构建器里指定新线程组从属于哪个线程组。若在创建一个线程组的 

时候没有指定它的归属,则同样会自动成为系统线程组的一名属下。因此,一个应用程序中的所有线程组最 

终都会将系统线程组作为自己的“父”。  

之所以要提出“线程组”的概念,很难从字面上找到原因。这多少为我们讨论的主题带来了一些混乱。一般 

地说,我们认为是由于“安全”或者“保密”方面的理由才使用线程组的。根据 Arnold 和 Gosling 的说法: 

 “线程组中的线程可以修改组内的其他线程,包括那些位于分层结构最深处的。一个线程不能修改位于自己 

所在组或者下属组之外的任何线程”(注释①)。然而,我们很难判断“修改”在这儿的具体含义是什么。 

下面这个例子展示了位于一个“叶子组”内的线程能修改它所在线程组树的所有线程的优先级,同时还能为 

这个“树”内的所有线程都调用一个方法。  

  

①:《The Java Programming Language》第 179 页。该书由 Arnold 和 Jams Gosling 编著,Addison…Wesley 

于 1996 年出版  

  

//: TestAccess。java  

// How threads can access other threads  

// in a parent thread group  

  

public class TestAccess {  

  public static void main(String'' args) {  

    ThreadGroup   

      x = new ThreadGroup(〃x〃);  

      y = new ThreadGroup(x; 〃y〃);  

      z = new ThreadGroup(y; 〃z〃);  

    Thread  

      one = new TestThread1(x; 〃one〃);  

      two = new TestThread2(z; 〃two〃);  

  }  

}  

  

class TestThread1 extends Thread {  

  private int i;  

  TestThread1(ThreadGroup g; String name) {  

    super(g; name);  

  }  

  void f() {  

    i++; // modify this thread  

    System。out。println(getName() + 〃 f()〃);  

  }  

}  

  



                                                                                     525 


…………………………………………………………Page 527……………………………………………………………

class TestThread2 extends TestThread1 {  

  TestThread2(ThreadGroup g; String name) {  

    super(g; name);  

    start();  

  }  

  public void run() {  

    ThreadGroup g =  

      getThreadGroup()。getParent()。getParent();  

    g。list();  

    Thread'' gAll = new Thread'g。act iveCount()';  

    g。enumerate(gAll);  

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

      gAll'i'。setPriority(Thread。MIN_PRIORITY);  

      ((TestThread1)gAll'i')。f();  

    }  

    g。list();  

  }  

} ///:~  

  

在main()中,我们创建了几个ThreadGroup (线程组),每个都位于不同的“叶”上:x 没有参数,只有它 

的名字(一个String),所以会自动进入“system”(系统)线程组;y 位于x 下方,而 z位于y 下方。注 

意初始化是按照文字顺序进行的,所以代码合法。  

有两个线程创建之后进入了不同的线程组。其中,TestThread1 没有一个 run()方法,但有一个f(),用于通 

知线程以及打印出一些东西,以便我们知道它已被调用。而TestThread2 属于TestThread1 的一个子类,它 

的run()非常详尽,要做许多事情。首先,它获得当前线程所在的线程组,然后利用getParent()在继承树中 

向上移动两级(这样做是有道理的,因为我想把TestThread2 在分级结构中向下移动两级)。随后,我们调 

用方法 activeCount() ,查询这个线程组以及所有子线程组内有多少个线程,从而创建由指向Thread 的句柄 

构成的一个数组。enumerate()方法将指向所有这些线程的句柄置入数组 gAll 里。然后在整个数组里遍历, 

为每个线程都调用 f()方法,同时修改优先级。这样一来,位于一个“叶子”线程组里的线程就修改了位于 

父线程组的线程。  

调试方法 list()打印出与一个线程组有关的所有信息,把它们作为标准输出。在我们对线程组的行为进行调 

查的时候,这样做是相当有好处的。下面是程序的输出:  

  

java。lang。ThreadGroup'name=x;maxpri=10'  

    Thread'one;5;x'  

    java。lang。ThreadGroup'name=y;maxpri=10'  

        java。lang。ThreadGroup'name=z;maxpri=10'  

            Thread'two;5;z'  

one f()  

two f()  

java。lang。ThreadGroup'name=x;maxpri=10'  

    Thread'one;1;x'  

    java。lang。ThreadGroup'name=y;maxpri=10'  

        java。lang。ThreadGroup'name=z;maxpri=10'  

            Thread'two;1;z'  

  

list()不仅打印出 ThreadGroup 或者Thread 的类名,也打印出了线程组的名字以及它的最高优先级。对于线 

程,则打印出它们的名字,并接上线程优先级以及所属的线程组。注意 list()会对线程和线程组进行缩排处 

理,指出它们是未缩排的线程组的“子”。  

大家可看到 f()是由TestThread2 的run()方法调用的,所以很明显,组内的所有线程都是相当脆弱的。然 

而,我们只能访问那些从自己的system 线程组树分支出来的线程,而且或许这就是所谓“安全”的意思。我 

们不能访问其他任何人的系统线程树。  



                                                                                         526 


…………………………………………………………Page 528……………………………………………………………

  

1。 线程组的控制  

抛开安全问题不谈,线程组最有用的一个地方就是控制:只需用单个命令即可完成对整个线程组的操作。下 

面这个例子演示了这一点,并对线程组内优先级的限制进行了说明。括号内的注释数字便于大家比较输出结 

果:  

  

//: ThreadGroup1。java  

// How thread groups control priorities  

// of the threads inside them。  

  

public class ThreadGroup1 {  

  public static void main(String'' args) {  

    // Get the system thread & print its Info:  

    ThreadGroup sys =   

      Thread。currentThread()。getThreadGroup();  

    sys。list(); // (1)  

    // Reduce the system thread group priority:  

    sys。setMaxPriority(Thread。MAX_PRIORITY 1);  

    // Increase the main thread priority:  

    Thread curr = Thread。currentThread();  

    curr。setPriority(curr。getPriority() + 1);  

    sys。list(); // (2)  

    // Attempt to set a new group to the max:  

    ThreadGroup g1 = new ThreadGroup(〃g1〃);  

    g1。setMaxPriority(Thread。MAX_PRIORITY);  

    // Attempt to set a new thread to the max:  

    Thread t = new Thread(g1; 〃A〃);  

    t。setPriority(Thread。MAX_PRIORITY);  

    g1。list(); // (3)  

    // Reduce g1's max priority; then attempt  

    // to increase it:  

    g1。setMaxPriority(Thread。MAX_PRIORITY 2);  

    g1。setMaxPriority(Thread。MAX_PRIORITY);  

    g1。list(); // (4)  

    // Attempt to set a new thread to the max:  

    t = new Thread(g1; 〃B〃);  

    t。setPriority(Thread。MAX_PRIORITY);  

    g1。list(); // (5)  

    // Lower the max priority below the default  

    // thread priority:  

    g1。setMaxPriority(Thread。MIN_PRIORITY + 2);  

    // Look at a new thread's priority before  

    // and after changing it:  

    t = new Thread(g1; 〃C〃);  

    g1。list(); // (6)  

    t。setPriority(t。getPriority() …1);  

    g1。list(); // (7)  

    // Make g2 a child Threadgroup of g1 and  

    // try to increase its priority:  

    ThreadGroup g2 = new ThreadGroup(g1; 〃g2〃);  

    g2。list(); // (8)  

    g2。setMaxPriority(Thread。MAX_PRIORITY);  



                                                                                          527 


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