当前位置:课程学习>>第十章 多线程>>文本学习>>知识点一


知识点一  创建线程




一、多线程的概念

针对于多个执行的任务而言,使用线程可以把单个任务给分割开来。计算机执行某个任务一段时间后,能够执行另一个任务的一部分操作。通过这样的工作过程,可以使多个任务看起来并发执行。虽然在微观上,处理器在每一时刻仅能处理一项任务,但是通过线程执行方式,使得多项任务可以同时进行。

Java使程序开发人员能够运用并发性功能,可以指定应用程序中包含多个执行的线程,每个线程被设计成具有部分程序功能,并且能与其他线程并发执行。这种能力被称为多线程(multithreading)。

 举一个简单的例子,在收看在线视频的时候,用户当然不会希望在接受完整的视频文件后才开始播放,尤其是长度较大的文件。在这种情况下,多线程技术负责将文件下载和播放功能分别设计在两个线程中,并且同时执行这两个线程。在线程执行过程中还要处理两者的执行关系,以避免播放过程中的不连续等问题。另外,较常见的还有多线程下载的例子,比如网际快车(flashget)和迅雷等工具,将文件下载过程分解成多个线程同时执行,从而提高了文件下载的效率。

为了更好的理解多线程的含义,来看一个实例。

【例10.1】编写一个程序,用以绘制小球在屏幕内弹跳的动作过程;同时提供一个按钮,来控制小球运动的开始和停止。

//Bouncer.java

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class Bouncer extends JFrame implements ActionListener {

  JPanel canvas = new JPanel();

  JPanel btnPanel = new JPanel();

  JButton startBtn = new JButton("start");

  JButton stopBtn = new JButton("stop");

  public Bouncer() {

    getContentPane().add(canvas, BorderLayout.CENTER);

    getContentPane().add(btnPanel, BorderLayout.SOUTH);

    btnPanel.add(startBtn);

    btnPanel.add(stopBtn);

    startBtn.addActionListener(this);

    stopBtn.addActionListener(this);

}

public static void main(String[] args) {

    Bouncer bouncer = new Bouncer();

    bouncer.setTitle("Bouncer");

    bouncer.setSize(300, 200);

    bouncer.setVisible(true);

}

public void actionPerformed(ActionEvent e) {

  if (e.getSource() == startBtn) {

    Ball ball = new Ball(canvas);

    ball.bounce();

  }

  if (e.getSource() == stopBtn)

    System.exit(0);

  }

}

class Ball {

  private JPanel canvas;

  private int radio;

  private int x_pos, y_pos;

  private int x_dis, y_dis;

  private int c_width, c_height;

  public Ball(JPanel c) {

    canvas = c;

    c_width = canvas.getWidth();

    c_height = canvas.getHeight();

    radio = 6;

    // 小球起始位置取随机值

    x_pos = (int) (Math.random() * c_width);

    y_pos = (int) (Math.random() * c_height);

    // 每次移动距离为半径/2

    x_dis = y_dis = radio / 2;

  }

  public void draw() {

    Graphics g = canvas.getGraphics();

    g.fillOval(x_pos, y_pos, radio, radio);

    g.dispose();

  }

  public void move() {

    Graphics g = canvas.getGraphics();

    g.setXORMode(canvas.getBackground());

    g.fillOval(x_pos, y_pos, radio, radio);

    x_pos += x_dis;

    y_pos += y_dis;

    if ((x_pos <= 0) || (x_pos >= c_width - x_dis))

      x_dis *= -1;

    if ((y_pos <= 0) || (y_pos >= c_height - y_dis))

      y_dis *= -1;

    g.fillOval(x_pos, y_pos, radio, radio);

    g.dispose();

  }

  public void bounce() {

    draw();

    while (1 == 1) {

    move();

    for (int j = 1; j <= 1000000; j++) ;

  }

 }

}

在实例中,绘制小球时采用XORMode方式,即在自身位置重复绘制对象时会消除原有的痕迹。程序中的小球初始位置是随机的,开始运动后将在画布内来回弹跳,draw方法中的for循环作用是调整小球的运动速度。

程序的本意是想通过按钮来控制小球的启动和停止。但是,在点击start按钮后,while循环之后的语句将不会被执行,点击stop按钮也就不可能实现,这是由于程序会一直在while循环内反复执行。为了解决这个问题,需要利用多线程的知识,在下面的内容中将逐步对多线程的内容展开介绍。

二、线程体的实现

Java提供了两种方法来创建多线程,一种是通过Thread类进行派生,另一种是实现Runnable接口。

1. 线程类Thread

Java通过java.lang.Thread类来支持多线程,在Thread类中封装了独立的有关线程执行的数据和方法。定义Thread类的派生类,这是创建线程最简单的方法。

【例10.2】利用Thread类实现多线程。

//CreateThread.java

public class CreateThread {

  public static void main(String[] args) {

    MyThread thread1 = new MyThread("Thread 0");

    MyThread thread2 = new MyThread("Thread 1");

    thread1.start();

    thread2.start();

  }

}

class MyThread extends Thread {

  private String id;

  public MyThread(String str) {

    id = str;

  }

  public void run() {

    int i = 0;

    for (int j = 0; j <= 100; j++) {

      System.out.println("I am " + id + "--I have run " + i + " times");

      i++;

    }

    System.out.println(id + " is end!");

  }

}

Thread类中run方法负责完成线程的具体工作,通过调用线程对象的start方法来启动线程的run方法。注意,线程工作中不能保证执行的顺序,例10.2的运行过程中线程0和线程1的数据是交替显示的,二者的结束顺序也是不可确定的。

2. Runnable接口

由于Java不支持多重继承,所以某个派生类不能再从Thread进行继承来实现线程的功能。此时要实现多线程,需要声明java.lang.Runnable接口,在Runnable接口中同样包含run方法。

【例10.3】利用Runnable接口实现多线程。

//CreateThread2.java

public class CreateThread2 {

  public static void main(String[] args) {

  Thread thread1 = new Thread(new MyThread2("Thread 0"));

  Thread thread2 = new Thread(new MyThread2("Thread 1"));

  thread1.start();

  thread2.start();

  }

}

class MyThread2 implements Runnable {

  private String id;

  public MyThread2(String str) {

    id = str;

  }

  public void run() {

    int i = 0;

    for (int j = 0; j <= 100; j++) {

      System.out.println("I am " + id + "--I have run " + i + " times");

      i++;

    }

    System.out.println(id + " is end!");

  }

}

MyThread2类实现了Runnable接口,将MyThread2的实例作为参数传递给Thread类的构造方法,是创建线程的另外一种方法。

 

进入知识点二学习