回响敏捷的用户界面
作为我们的起点,请思考一个需要执行某些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++)); } } 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的计较时间实际却是在所有线程间分摊的。
线程机制几多低落了一些计较效率,但无论措施的设计,资源的平衡,照旧用户操纵的利便性,都从中得到了庞大的好处。综合思量,这一机制长短常有代价的。虽然,假如原来就安装了多块CPU,那么操纵系统可以或许自行抉择为差异的CPU分派哪些线程,措施的总体运行速度也会变得更快(所有这些都要求操纵系统以及应用措施的支持)。多线程和多任务是充实发挥多处理惩罚机系统本领的一种最有效的方法。