在java语言中,可以采用两种方式产生线程:
- 通过继承Thread类构造线程。
- 实现一个Runnable接口。
此处仅讨论第一种方面,通过此方法创建一个线程的步骤:
- 创建一个扩展(extends)Thread类
- 用要在这个线程中执行的代码覆盖Thread类的run()方法
- 用关键字new创建所定义的线程类的一个对象
- 调用该对象的start()方法启动线程
线程启动后自动执行run()方法,执行完毕后进入终止状态。java中有关线程暂停和恢复的几个方法:
- sleep(),是Thread类中的方法,指定线程休眠一段时间
- yield(),是Thread类中的方法,暂时中止当前正在执行的线程对象的运行。若存下其他同优先级的线程,则随即调用下一个同优先级的线程;若不存在这个被中断的程序继续。
- wait(),Object类中声明的方法,使线程进入等待状态,直到被另一线程唤醒。
- notify(),Object类中声明的方法,把线程状态的变化通知并唤醒另一等待线程。
一种在任何时刻都能终止线程执行的简单机制:
- 增加一个布尔变量running到这个Thread类中,并初始化为false
- 覆盖start()方法,首先将running置为true,然后调用super.start()方法
- 提供一个公共的(public)方法halt(),它将running变量置为false
- 在run()方法中使用while()循环,运行线程要执行的代码。
例.一个多线程的实例,模拟了一个笼子内有20只鸟在里面移动,每个“鸟”是一个扩展Thread的类,负责控制它的移动。
“鸟”这个类的代码:
package xql;
import java.awt.*;
import java.awt.event.*;
//创建扩展Thread类的鸟类,可以独立执行自己的线程
public class Bird extends Thread{
private int xdir=1*(1-2*(int)Math.round(Math.random())); //随机产生x轴的移动方向
private int ydir=1*(1-2*(int)Math.round(Math.random())); //随机产生y轴的移动方向
private boolean running = false;
private Cage cage = null;
protected int x,y; //设置两个域x,y,作为鸟的当前坐标
Image bird=Toolkit.getDefaultToolkit().getImage("src/bird.PNG");
public Bird(Cage _cage,int _x,int _y){
x = _x;
y = _y;
cage=_cage;
start();
}
public void start(){ //覆盖start()方法
running = true;
super.start();
}
public void halt(){
running = false;
}
public void run(){
while(running){
move(); //移动鸟的位置
try{
sleep(12); //调用sleep()方法,让出时间使操作系统去移动其他鸟
}catch(InterruptedException ie){
System.err.println("Thread interruoted");
}
cage.repaint(); //刷新画面
}
}
private void move() { //定义移动“鸟”的方法
x+=xdir;
y+=ydir;
if(x>cage.getSize().width){ //若横向移动超出范围,将x轴移动方向反向
x=cage.getSize().width;
xdir*=(-1);
}
if(x<0) xdir*=(-1);
if(y>cage.getSize().height){ //若纵向移动超出范围,将y轴移动方向反向
y=cage.getSize().height;
ydir*=(-1);
}
if(y<0) ydir*=(-1);
}
public void draw(Graphics g){ //在cage窗口中的(x,y)处画出一个大小为30px,40px的鸟
g.drawImage(bird, x, y,30,40,cage);
}
}
“笼子”这个类的代码:
package xql;
import java.awt.*;
import java.awt.event.*;
//创建实现"笼子"的类,它是一个扩展Frame类
public class Cage extends Frame implements ActionListener{
//定义 启动、终止“鸟”的运动,以及退出程序的三个按钮
private Button quit = new Button("quit");
private Button start = new Button("start");
private Button stop = new Button("stop");
private Bird birds[] = new Bird[20]; //创建20个“鸟”对象存在数组中
Image bird=Toolkit.getDefaultToolkit().getImage("src/bird.jpg");
public Cage(){
super("Cage With Birds"); //创建一个标题为“Cage With Birds”的窗口
setLayout(new FlowLayout()); //设置窗口的布局为流式布局
add(quit);quit.addActionListener(this);
add(start);start.addActionListener(this);
add(stop);stop.addActionListener(this);
validate(); //重整窗口组件,使当调整窗口的大小时,组件的位置也跟着变化
setSize(500,500); //设置窗口的大小
setVisible(true); //设置窗口在运行时可见
for(int i=0;i<birds.length;i++){ //为这二十个“鸟”对象随机地设置起始位置
int x = (int)(getSize().width*Math.random());
int y = (int)(getSize().height*Math.random());
birds[i] = new Bird(this,x,y);
}
}
public void actionPerformed(ActionEvent ae){ //实现ActionListener接口
if(ae.getSource()==stop) //点击stop,调用halt()方法将running置为false,结束线程
for(int i=0;i<birds.length;i++)
birds[i].halt();
if(ae.getSource()==start) //点击start,先结束各线程,再重新再原位置新建“鸟”对象
for(int i=0;i<birds.length;i++){
birds[i].halt();
birds[i] = new Bird(this,birds[i].x,birds[i].y);
}
if(ae.getSource()==quit){ //点击quit关闭所有窗口
System.exit(0);
}
}
public void paint(Graphics g){ //定义paint()函数画出20个鸟
for(int i=0;i<birds.length;i++)
if(birds[i]!=null)
birds[i].draw(g);
}
public static void main(String args[]){
Cage table = new Cage();
}
}
当单击start按钮后,每个Bird开始执行它自己的rn()方法;每个Bird的run()方法不停地重新计算它的新坐标,休眠120ms后,再调用table类的repaint()方法。repaint()方法的调用导致了图像的更新,从而产生鸟移动的感觉。
运行效果: