例6.1 通过继承类Thread构造线程体
  class SimpleThread extends Thread {
  public SimpleThread(String str) {
   super(str); //调用其父类的构造方法
  }
  public void run() { //重写run方法
   for (int i = 0; i < 10; i++) {
    System.out.println(i + " " + getName());
             //打印次数和线程的名字

    try {
      sleep((int)(Math.random() * 1000));
             //线程睡眠,把控制权交出去

    } catch (InterruptedException e) {}
  }

     System.out.println("DONE! " + getName());
             //线程执行结束

    }
  }
  public class TwoThreadsTest {
   public static void main (String args[]) {
    new SimpleThread("First").start();
             //第一个线程的名字为First
    new SimpleThread("Second").start();
             //第二个线程的名字为Second

}
}

   运行结果:
    0 First
    0 Second
    1 Second
    1 First
    2 First
    2 Second
    3 Second
    3 First
    4 First
    4 Second
    5 First
    5 Second
    6 Second
    6 First
    7 First
    7 Second
    8 Second
    9 Second
    8 First
    DONE! Second
    9 First
    DONE! First

  仔细分析一下运行结果,会发现两个线程是交错运行的,感觉就象是两个线程在同时运行。但是实际上一台计算机通常就只有一个CPU,在某个时刻只能是只有一个线程在运行,而java语言在设计时就充分考虑到线程的并发调度执行。对于程序员来说,在编程时要注意给每个线程执行的时间和机会,主要是通过让线程睡眠的办法(调用sleep()方法)来让当前线程暂停执行,然后由其它线程来争夺执行的机会。如果上面的程序中没有用到sleep()方法,则就是第一个线程先执行完毕,然后第二个线程再执行完毕。所以用活sleep()方法是学习线程的一个关键。

 例6.2 通过接口构造线程体
   public class Clock extends java.applet.Applet implements Runnable {//实现接口
      Thread clockThread;
      public void start() {
         //该方法是Applet的方法,不是线程的方法

      if (clockThread == null) {
         clockThread = new Thread(this, "Clock");
         /*线程体是Clock对象本身,线程名字为"Clock"*/
         clockThread.start(); //启动线程
         }
      }

      public void run() { //run()方法中是线程执行的内容
         while (clockThread != null) {
         repaint(); //刷新显示画面
         try {
           clockThread.sleep(1000);
           //睡眠1秒,即每隔1秒执行一次

          } catch (InterruptedException e){}
         }
      }

      public void paint(Graphics g) {
          Date now = new Date(); //获得当前的时间对象
          g.drawString(now.getHours() + ":" + now.getMinutes()+ ":" +now.getSeconds(), 5, 10);//显示当前时间
      }

      public void stop() {
        //该方法是Applet的方法,不是线程的方法
          clockThread.stop();
          clockThread = null;
      }
   }

  上面这个例子是通过每隔1秒种就执行线程的刷新画面功能,显示当前的时间;看起来的效果就是一个时钟,每隔1秒就变化一次。由于采用的是实现接口Runnable的方式,所以该类Clock还继承了Applet, Clock就可以Applet的方式运行。

  构造线程体的两种方法的比较:

  1. 使用Runnable接口
   1) 可以将CPU,代码和数据分开,形成清晰的模型;
   2) 还可以从其他类继承;
   3) 保持程序风格的一致性。

  2. 直接继承Thread类
   1) 不能再从其他类继承;
   2) 编写简单,可以直接操纵线程,无需使用Thread.currentThread()。