针对用户界面的多线程
当前位置:以往代写 > JAVA 教程 >针对用户界面的多线程
2019-06-14

针对用户界面的多线程

针对用户界面的多线程

此刻,我们也许能用一个线程办理在Counter1.java中呈现的问题。回收的一个能力即是在一个线程的run()要领中安排“子任务”——亦即位于go()内的轮回。一旦用户按下Start按钮,线程就会启动,但顿时竣事线程的建设。这样一来,尽量线程仍在运行,但措施的主要事情却能得以继承(等待并响应用户界面的事件)。下面是详细的代码:
 

//: Counter2.java
// A responsive user interface with threads
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

class SeparateSubTask extends Thread {
  private int count = 0;
  private Counter2 c2;
  private boolean runFlag = true;
  public SeparateSubTask(Counter2 c2) {
    this.c2 = c2;
    start();
  }
  public void invertFlag() { runFlag = !runFlag;}
  public void run() {
    while (true) {
     try {
      sleep(100);
     } catch (InterruptedException e){}
     if(runFlag) 
       c2.t.setText(Integer.toString(count++));
    }
  }
} 

public class Counter2 extends Applet {
  TextField t = new TextField(10);
  private SeparateSubTask sp = null;
  private Button 
    onOff = new Button("Toggle"),
    start = new Button("Start");
  public void init() {
    add(t);
    start.addActionListener(new StartL());
    add(start);
    onOff.addActionListener(new OnOffL());
    add(onOff);
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(sp == null)
        sp = new SeparateSubTask(Counter2.this);
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(sp != null)
        sp.invertFlag();
    }
  }
  public static void main(String[] args) {
    Counter2 applet = new Counter2();
    Frame aFrame = new Frame("Counter2");
    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);
  }
} ///:~

此刻,Counter2酿成了一个相当直接的措施,它的独一任务就是配置并打点用户界面。但假利用户此刻按下Start按钮,却不会真正挪用一个要领。此时不是建设类的一个线程,而是建设SeparateSubTask,然后继承Counter2事件轮回。留意此时会生存SeparateSubTask的句柄,以便我们按下onOff按钮的时候,能正常地切换位于SeparateSubTask内部的runFlag(运行符号)。随后谁人线程便可启动(当它看到符号的时候),然后将本身中止(亦可将SeparateSubTask设为一个内部类来到达这一目标)。
SeparateSubTask类是对Thread的一个简朴扩展,它带有一个构建器(个中生存了Counter2句柄,然后通过挪用start()来运行线程)以及一个run()——本质上包括了Counter1.java的go()内的代码。由于SeparateSubTask知道本身容纳了指向一个Counter2的句柄,所以可以或许在需要的时候参与,并会见Counter2的TestField(文本字段)。
按下onOff按钮,险些当即能获得正确的响应。虽然,这个响应其实并不是“当即”产生的,它究竟和那种由“间断”驱动的系统差异。只有线程拥有CPU的执行时间,并留意到标志已产生改变,计数器才会遏制。

1. 用内部类改进代码
下面说说题外话,请各人留意一下SeparateSubTask和Counter2类之间产生的团结行为。SeparateSubTask同Counter2“亲密”地团结到了一起——它必需持有指向本身“父”Counter2工具的一个句柄,以便本身能回和谐哄骗它。但两个类并不是真的归并为单唯一个类(尽量在下一节中,我们会讲到Java确实提供了归并它们的要领),因为它们各自做的是差异的工作,并且是在差异的时间建设的。但不管奈何,它们依然细密地团结到一起(更精确地说,应该叫“连系”),所以使措施代码几多显得有些鸠拙。在这种环境下,一个内部类可以显著改进代码的“可读性”和执行效率:
 

//: Counter2i.java
// Counter2 using an inner class for the thread
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class Counter2i extends Applet {
  private class SeparateSubTask extends Thread {
    int count = 0;
    boolean runFlag = true;
    SeparateSubTask() { start(); }
    public void run() {
      while (true) {
       try {
        sleep(100);
       } catch (InterruptedException e){}
       if(runFlag) 
         t.setText(Integer.toString(count++));
      }
    }
  } 
  private SeparateSubTask sp = null;
  private TextField t = new TextField(10);
  private Button 
    onOff = new Button("Toggle"),
    start = new Button("Start");
  public void init() {
    add(t);
    start.addActionListener(new StartL());
    add(start);
    onOff.addActionListener(new OnOffL());
    add(onOff);
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(sp == null)
        sp = new SeparateSubTask();
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(sp != null)
        sp.runFlag = !sp.runFlag; // invertFlag();
    }
  }
  public static void main(String[] args) {
    Counter2i applet = new Counter2i();
    Frame aFrame = new Frame("Counter2i");
    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);
  }
} ///:~

#p#分页标题#e#

这个SeparateSubTask名字不会与前例中的SeparateSubTask斗嘴——纵然它们都在沟通的目次里——因为它已作为一个内部类埋没起来。各人亦可看到内部类被设为private(私有)属性,这意味着它的字段和要领都可得到默认的会见权限(run()除外,它必需设为public,因为它在基本类中是果真的)。除Counter2i之外,其他任何方面都不行会见private内部类。并且由于两个类细密团结在一起,所以很容易放宽它们之间的会见限制。在SeparateSubTask中,我们可看到invertFlag()要领已被删去,因为Counter2i此刻可以直接会见runFlag。
另外,留意SeparateSubTask的构建器已获得了简化——它此刻独一的用外就是启动线程。Counter2i工具的句柄仍象以前那样得以捕捉,但不再是通过人工通报和引用外部工具来到达这一目标,此时的内部类机制可以自动顾问它。在run()中,可看到对t的会见是直接举办的,好像它是SeparateSubTask的一个字段。父类中的t字段此刻可以酿成private,因为SeparateSubTask能在未获任何非凡许可的前提下自由地会见它——并且无论如何都该尽大概地把字段酿成“私有”属性,以防来自类外的某种气力不慎地改变它们。
无论在什么时候,只要留意到类彼此之间团结得较量细密,就可思量操作内部类来改进代码的编写与维护。

    关键字:

在线提交作业