一.基本概念
虽然各种操作系统(Unix/Linux、Windows系列等)都支持多线程,但若要用C、C++或其他语言编写多线程程序是十分困难的,因为它们对数据同步的支持不充分。
对多线程的综合支持是Java语言的一个重要特色,它提供了Thread类来实现多线程。在Java中,线程可以认为是由三部分组成的:
虚拟CPU,封装在java.lang.Thread类中,它控制着整个线程的运行;
执行的代码,传递给Thread类,由Thread类控制顺序执行;
处理的数据,传递给Thread类,是在代码执行过程中所要处理的数据。
二.线程的创建
Java的线程是通过Java的软件包Java.lang中定义的类Thread来实现的。当生成一个Thread类的对象之后,就产生了一个线程,通过该对象实例,可以启动线程、终止线程、或者暂时挂起它等。
Thread类本身只是线程的虚拟CPU,线程所执行的代码(或者说线程所要完成的功能)是通过方法run()(包含在一个特定的对象中)来完成的,方法run()称为线程体。实现线程体的特定对象是在初始化线程时传递给线程的。在一个线程被建立并初始化以后,Java的运行时系统就自动调用run( )方法,正是通过run( )方法才使得建立线程的目的得以实现。
通常,run( )方法是一个循环,例如一个播放动画的线程要循环显示一系列图片。有时,run( )方法会执行一个时间较长的操作,例如下载并播放一个JPEG格式的电影。
先来看看线程对象的初始化,类Thread的构造方法如下:
public Thread( ThreadGroup group, Runnable target, String name)
group指明了线程所属的线程组;
target是线程体run()方法所在的对象;
name是线程的名称。
target必须实现接口Runnable。在接口Runnable中只定义了一个方法void run()作为线程体。任何实现接口Runnable的地对象都可以作为一个线程的目标对象。
类Thread本身也实现了接口Runnable,因此,上述构造方法中各参数都可以为null,并且可以有两种方法构造用户自己的run( )方法。
归结:(创建方法有两种)
方法一:
定义一个线程类,它继承类Thread并重写其中的方法run()。这时在初始化这个类的实例时,目标对象target可以为null,表示这个实例本身具有线程体。由于Java只支持单继承,用这种方法定义的类不能再继承其他类。
class SimpleThread extends Thread
{
public SimpleThread(String str)
{
super(str);
}
public void 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());
}
}
方法二:
提供一个实现接口Runnable的类作为线程的目标对象。在初始化一个Thread类或子类生成线程实例时,把目标对象传递给这个线程实例,由该目标对象提供线程体run()方法。这时,实现接口Runnable的类还可以再继承其他类。
public class Clock extends java.applet.Applet implements Runnable
{
Thread clockThread;
public void start()
{
if (clockThread == null)
{
clockThread = new Thread(this, "Clock");
clockThread.start();
}
}
public void run()
{
while (clockThread != null)
{
repaint();
try{
clockThread.sleep(1000);
}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()
{
clockThread.stop();
clockThread = null;
}
}
使用runable接口的好处:
使用Runnable接口可以将线程的虚拟CPU、代码和数据分开,形成一个比较清晰的模型。
使用Runnable接口使得包含线程体的类还可以继承其他类。
直接继承Thread类以后不能再继承其他类,但编写简单,并可直接操纵线程;使用Runnable接口时,若要在run()方法中操纵线程,必须使用Thread.currentThread()方法。
在具体应用中,采用哪种方法来构造线程体要根据具体情况而定。通常,当一个线程体所在的类已经继承了另一个类时,就应该用实现Runnable接口的方法。