java建造多个线程
此刻思量一下建设多个差异的线程的问题。我们不行用前面的例子来做到这一点,所以必需倒退归去,操作从Thread担任的多个独立类来封装run()。但这是一种更通例的方案,并且更易领略,所以尽量前例展现了我们常常都能看到的编码样式,但并不推荐在大大都环境下都那样做,因为它只是稍微巨大一些,并且机动性稍低一些。
下面这个例子用计数器和切换按钮再现了前面的编码样式。但这一次,一个特定计数器的所有信息(按钮和文本字段)都位于它本身的、从Thread担任的工具内。Ticker中的所有字段都具有private(私有)属性,这意味着Ticker的详细实现方案可按照实际环境任意修改,个中包罗修改用于获取和显示信息的数据组件的数量及范例。建设好一个Ticker工具今后,构建器便请求一个AWT容器(Container)的句柄——Ticker用本身的可视组件填充谁人容器。回收这种方法,今后一旦改变了可视组件,利用Ticker的代码便不需要另行修改一道。
//: Counter4.java // If you separate your thread from the main // class, you can have as many threads as you // want. import java.awt.*; import java.awt.event.*; import java.applet.*; class Ticker extends Thread { private Button b = new Button("Toggle"); private TextField t = new TextField(10); private int count = 0; private boolean runFlag = true; public Ticker(Container c) { b.addActionListener(new ToggleL()); Panel p = new Panel(); p.add(t); p.add(b); c.add(p); } class ToggleL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = !runFlag; } } public void run() { while (true) { if(runFlag) t.setText(Integer.toString(count++)); try { sleep(100); } catch (InterruptedException e){} } } } public class Counter4 extends Applet { private Button start = new Button("Start"); private boolean started = false; private Ticker[] s; private boolean isApplet = true; private int size; public void init() { // Get parameter "size" from Web page: if(isApplet) size = Integer.parseInt(getParameter("size")); s = new Ticker[size]; for(int i = 0; i < s.length; i++) s[i] = new Ticker(this); start.addActionListener(new StartL()); add(start); } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(!started) { started = true; for(int i = 0; i < s.length; i++) s[i].start(); } } } public static void main(String[] args) { Counter4 applet = new Counter4(); // This isn't an applet, so set the flag and // produce the parameter values from args: applet.isApplet = false; applet.size = (args.length == 0 ? 5 : Integer.parseInt(args[0])); Frame aFrame = new Frame("Counter4"); aFrame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(200, applet.size * 50); applet.init(); applet.start(); aFrame.setVisible(true); } } ///:~
Ticker不只包罗了本身的线程处理惩罚机制,也提供了节制与显示线程的东西。可按本身的意愿建设任意数量的线程,毋需明晰地建设窗口化组件。
在Counter4中,有一个名为s的Ticker工具的数组。为得到最大的机动性,这个数组的长度是用措施片参数打仗Web页而初始化的。下面是网页中长度参数大抵的样子,它们嵌于对措施片(applet)的描写内容中:
<applet code=Counter4 width=600 height=600>
<param name=size value="20">
</applet>
个中,param,name和value是所有Web页都合用的要害字。name是指措施中对参数的一种引用称呼,value可以是任何字串(并不只仅是理会成一个数字的对象)。
我们留意到对数组s长度的判定是在init()内部完成的,它没有作为s的内嵌界说的一部门提供。换言之,不行将下述代码作为类界说的一部门利用(应该位于任何要领的外部):
inst size = Integer.parseInt(getParameter("Size"));
Ticker[] s = new Ticker[size]
可把它编译出来,但会在运行期获得一个空指针违例。但若将getParameter()初始化移入init(),则可正常事情。措施片框架会举办须要的启动事情,以便在进入init()前收集好一些参数。
另外,上述代码被同时配置成一个措施片和一个应用(措施)。在它是应用措施的环境下,size参数可从呼吁行里提取出来(不然就提供一个默认的值)。
数组的长度建好今后,就可以建设新的Ticker工具;作为Ticker构建器的一部门,用于每个Ticker的按钮和文本字段就会插手措施片。
按下Start按钮后,会在整个Ticker数组里遍历,并为每个Ticker挪用start()。记着,start()会举办须要的线程初始化事情,然后为谁人线程挪用run()。
ToggleL监督器只是简朴地切换Ticker中的标志,一旦对应线程今后需要修改这个标志,它会作出相应的回响。
这个例子的一个长处是它使我们可以或许利便地建设由单独子任务组成的大型荟萃,并以监督它们的行为。在这种环境下,我们会发明跟着子任务数量的增多,呆板显示出来的数字大概会呈现更大的分歧,这是由于为线程提供处事的方法造成的。
亦可试着体验一下sleep(100)在Ticker.run()中的重要浸染。若删除sleep(),那么在按下一个切换按钮前,环境仍然会希望精采。按下按钮今后,谁人特定的线程就会呈现一个失败的runFlag,并且run()会深深地陷入一个无限轮回——很难在多任务处理惩罚期间中止退出。因此,措施对用户操纵的回响敏捷度会大幅度低落。