例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()。
|