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

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

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





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