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

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

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


的环境,因此不但考虑到同其它的应用程序构建环境竞争,而且Java 还促进它们的发展。这些工具被认真地 

使用,它们必须支持Java Beans。这意味着一个平等的应用领域:如果一个更好的应用程序构建工具出现, 

我们不需要去约束它就可以使用——我们可以采用并移动到新的工具上工作即可,这会提高我们的工作效 

率。这种竞争的环境对应用程序构建工具来说从未出现过,这种竞争能真正提高程序设计者的工作效率。  



                                                                 485 


…………………………………………………………Page 487……………………………………………………………

13。21 练习  



(1)创建一个有文字字段和三个按钮的程序片。当我们按下每个按钮时,使不同的文字显示在文字段中。  

(2)增加一个复选框到练习 1 创建的程序中,捕捉事件,并插入不同的文字到文字字段中。  

(3)创建一个程序片并增加所有导致action()被调用的组件,然后捕捉他们的事件并在文字字段中为每个组 

件显示一个特定的消息。  

(4)增加可以被 handleEvent()方法测试事件的组件到练习3 中。过载handleEvent()并在文字字段中为每个 

组件显示特定的消息。  

(5)创建一个有一个按钮和一个TextField 的程序片。编写一个handleEvent() ,以便如果按钮有焦点,输入 

字符到将显示的TextField 中。  

(6)创建一个应用程序并将本章所有的组件增加主要的帧,包括菜单和对话框。  

(7)修改TextNew。java,以便字母在t2 中保持输入时的样子,取代自动变成大写。  

(8)修改CardLayout1。java 以便它使用Java 1。1 的事件模型。  

(9)增加Frog。class 到本章出现的清单文件中并运行jar 以创建一个包括Frog 和 BangBean 的JAR 文件。现 

在从SUN 公司处下载并安装 BDK 或者使用我们自己的可激活Bean 的程序构建工具并增加 JAR 文件到我们的环 

境中,因此我们可以测试两个 Bean 。  

(10)创建我们自己的包括两个属性:一个布尔值为“on”,另一个为整型“level”,称为Valve 的Java  

Bean 。创建一个清单文件,利用jar 打包我们的 Bean ,然后读入它到beanbox 或到我们自己的激活程序构建 

工具里,因此我们可以测试它。  

(11)修改Menus。java,以便它处理多级菜单。这要假设读者已经熟悉了 HTML 的基础知识。但那些东西并不 

难理解,而且有一些书和资料可供参考。  



                                                                    486 


…………………………………………………………Page 488……………………………………………………………

                                  第 14 章  多线程  



  

利用对象,可将一个程序分割成相互独立的区域。我们通常也需要将一个程序转换成多个独立运行的子任 

务。  

象这样的每个子任务都叫作一个“线程”(Thread)。编写程序时,可将每个线程都想象成独立运行,而且 

都有自己的专用CPU。一些基础机制实际会为我们自动分割CPU 的时间。我们通常不必关心这些细节问题, 

所以多线程的代码编写是相当简便的。  

这时理解一些定义对以后的学习狠有帮助。“进程”是指一种“自包容”的运行程序,有自己的地址空间。 

 “多任务”操作系统能同时运行多个进程(程序)——但实际是由于CPU 分时机制的作用,使每个进程都能 

循环获得自己的CPU 时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。“线程” 

是进程内部单一的一个顺序控制流。因此,一个进程可能容纳了多个同时执行的线程。  

多线程的应用范围很广。但在一般情况下,程序的一些部分同特定的事件或资源联系在一起,同时又不想为 

它而暂停程序其他部分的执行。这样一来,就可考虑创建一个线程,令其与那个事件或资源关联到一起,并 

让它独立于主程序运行。一个很好的例子便是“Quit ”或“退出”按钮——我们并不希望在程序的每一部分 

代码中都轮询这个按钮,同时又希望该按钮能及时地作出响应(使程序看起来似乎经常都在轮询它)。事实 

上,多线程最主要的一个用途就是构建一个“反应灵敏”的用户界面。  



14。1 反应灵敏的用户界面  



作为我们的起点,请思考一个需要执行某些CPU 密集型计算的程序。由于 CPU “全心全意”为那些计算服 

务,所以对用户的输入十分迟钝,几乎没有什么反应。在这里,我们用一个合成的applet/application (程 

序片/应用程序)来简单显示出一个计数器的结果:  

  

//: Counter1。java  

// A non…responsive user interface  

package c14;  

import java。awt。*;  

import java。awt。event。*;  

import java。applet。*;  

  

public class Counter1 extends Applet {  

  private int count = 0;  

  private Button   

    onOff = new Button(〃Toggle〃);  

    start = new Button(〃Start〃);  

  private TextField t = new TextField(10);  

  private boolean runFlag = true;  

  public void init() {  

    add(t);  

    start。addActionListener(new StartL());  

    add(start);  

    onOff。addActionListener(new OnOffL());  

    add(onOff);  

  }  

  public void go() {  

    while (true) {  

      try {  

        Thread。currentThread()。sleep(100);  

      } catch (InterruptedException e){}  

      if(runFlag)   

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



                                                                                      487 


…………………………………………………………Page 489……………………………………………………………

    }  

  }  

  class StartL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      go();  

    }  

  }  

  class OnOffL implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      runFlag = !runFlag;  

    }  

  }  

  public static void main(String'' args) {  

    Counter1 applet = new Counter1();  

    Frame aFrame = new Frame(〃Counter1〃);  

    aFrame。addWindowListener(  

      new WindowAdapter() {  

        public void windowClosing(WindowEvent e) {  

          System。exit(0);  

        }  

      });  

    aFrame。add(applet; BorderLayout。CENTER);  

    aFrame。setSize(300;200);  

    applet。init();  

    applet。start();  

    aFrame。setVisible(true);  

  }  

} ///:~  

  

在这个程序中,AWT 和程序片代码都应是大家熟悉的,第 13章对此已有很详细的交待。go()方法正是程序全 

心全意服务的对待:将当前的 count (计数)值置入TextField (文本字段)t,然后使count 增值。  

go() 内的部分无限循环是调用sleep()。sleep()必须同一个 Thread (线程)对象关联到一起,而且似乎每个 

应用程序都有部分线程同它关联(事实上,Java 本身就是建立在线程基础上的,肯定有一些线程会伴随我们 

写的应用一起运行)。所以无论我们是否明确使用了线程,都可利用Thread。currentThread()产生由程序使 

用的当前线程,然后为那个线程调用sleep()。注意,Thread。currentThread()是 Thread 类的一个静态方 

法。  

注意 sleep()可能“掷”出一个 InterruptException (中断违例)——尽管产生这样的违例被认为是中止线 

程的一种“恶意”手段,而且应该尽可能地杜绝这一做法。再次提醒大家,违例是为异常情况而产生的,而 

不是为了正常的控制流。在这里包含了对一个“睡眠”线程的中断,以支持未来的一种语言特性。  

一旦按下start 按钮,就会调用go()。研究一下go(),你可能会很自然地(就象我一样)认为它该支持多线 

程,因为它会进入“睡眠”状态。也就是说,尽管方法本身“睡着”了,CPU 仍然应该忙于监视其他按钮 

 “按下”事件。但有一个问题,那就是go()是永远不会返回的,因为它被设计成一个无限循环。这意味着 

actionPerformed()根本不会返回。由于在第一个按键以后便陷入 actionPerformed()中,所以程序不能再对 

其他任何事件进行控制(如果想出来,必须以某种方式“杀死”进程——最简便的方式就是在控制台窗口按 

Ctrl +C 键)。  

这里最基本的问题是go()需要继续执行自己的操作,而与此同时,它也需要返回,以便 actionPerformed() 

能够完成,而且用户界面也能继续响应用户的操作。但对象go()这样的传统方法来说,它却不能在继续的同 

时将控制权返回给程序的其他部分。这听起来似乎是一件不可能做到的事情,就象CPU 必须同时位于两个地 

方一样,但线程可以解决一切。“线程模型”(以及Java 中的编程支持)是一种程序编写规范,可在单独一 

个程序里实现几个操作的同时进行。根据这一机制,CPU 可为每个线程都分配自己的一部分时间。每个线程 

都“感觉”自己好象拥有整个 CPU,但CPU 的计算时间实际却是在所有线程间分摊的。  

线程机制多少降低了一些计算效率,但无论程序的设计,资源的均衡,还是用户操作的方便性,都从中获得 



                                                                                      488 


…………………………………………………………Page 490……………………………………………………………

了巨大的利益。综合考虑,这一机制是非常有价值的。当然,如果本来就安装了多块 CPU,那么操作系统能 

够自行决定为不同的CPU 分配哪些线程,程序的总体运行速度也会变得更快(所有这些都要求操作系统以及 

应用程序的支持)。多线程和多任务是充分发挥多处理机系统能力的一种最有效的方式。  



14。1。1 从线程继承  



为创建一个线程,最简单的方法就是从Thread 类继承。这个类包含了创建和运行线程所需的一切东西。 

Thread 最重要的方法是run()。但为了使用run(),必须对其进行过载或者覆盖,使其能充分按自己的吩咐 

行事。因此,run()属于那些会与程序中的其他线程“并发”或“同时”执行的代码。  

下面这个例子可创建任意数量的线程,并通过为每个线程分配一个独一无二的编号(由一个静态变量产 

生),从而对不同的线程进行跟踪。Thread 的run()方法在这里得到了覆盖,每通过一次循环,计数就减 

1——计数为 0 时则完成循环(此时一旦返回 run(),线程就中止运行)。  

  

//: SimpleThread。java  

// Very simple Threading example  

  

public class SimpleThread extends Thread {  

  private int countDown = 5;  

  private int threadNumber;  

  private static int threadCount = 0;  

  public SimpleThread() {  

    threadNumber = ++threadCount;  

    System。out。println(〃Making 〃 + threadNumber);  

  }  

  public void run() {  

    while(true) {  

      System。out。println(〃Thread 〃 +   

        threadNumber + 〃(〃 + countDown + 〃)〃);  

      if(……countDown == 0) return;  

    }  

  }  

  public static void main(String'' args) {  

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

      new SimpleThread()。start();  

    System。out。println(〃All Threads Started〃);  

  }  

} ///:~  

  

run()方法几乎肯定含有某种形式的循环——它们会一直持续到线程不再需要为止。因此,我们必须规定特定 

的条件,以便中断并退出这个循环(或者在上述的例子中,简单地从run()返回即可)。run()通常采用一种 

无限循环的形式。也就是说,通过阻止外部发出对线程的 stop()或者destroy()调用,它会永远运行下去 

 (直到程序完成)。  

在main()中,可看到创建并运行了大量线程。Thread 包含了一个特殊的方法,叫作 start(),它的作用是对 

线程进行特殊的初始化,然后调用 run()。所以整个步骤包括:调用构建器来构建对象,然后用start()配置 

线程,再调用run()。如果不调用start()——如果适当的话,可在构建器那样做——线程便永远不会启动。  

下面是该程序某一次运行的输出(注意每次运行都会不同):  

  

Making 1  

Making 2  

Making 3  

Making 4  

Making 5  

Thread 1(5)  



                                                                                         489 


…………………………………………………………Page 491……………………………………………………………

Thread 1(4)  

Thread 1(3)  

Thread 1(2)  

Thread 2(5)  

Thread 2(4)  

Thread 2(3)  

Thread 2(2)  

Thread 2(1)  

Thread 1(1)  

All Threads Started  

Thread 3(5)  

Thread 4(5)  

Thread 4(4)  

Thread 4(3)  

Thread 4(2)  

Thread 4(1)  

Thread 5(5)  

Thread 5(4)  

Thread 5(3)  

Thread 5(2)  

Thread 5(1)  

Thread 3(4)  

Thread 3(3)  

Thread 3(2)  

Thread 3(1)  

  

可注意到这个例子中到处都调用了 sleep(),然而输出结果指出每个线程都获得了属于自己的那一部分CPU 

执行时间。从中可以看出,尽管 sleep()依赖一个线程的存在来执行,但却与允许或禁止线程无关。它只不 

过是另一个不同的方法而已。  

亦可看出线程并不是按它们创建时的顺序运行的。事实上,CPU 处理一个现有线程集的顺序是不确定的—— 

除非我们亲自介入,并用Thread 的setPriority()方法调整它们的优先级。  

main()创建 Thread 对象时,它并未捕获任何一个对象的句柄。普通对象对于垃圾收集来说是一种 “公平竞 

赛”,但线程却并非如此。每个线程都会“注册”自己,所以某处实际存在着对它的一个引用。这样一来, 

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