Java虚拟机(Java Virtual Machine,JVM,是运行所有Java程序的抽象计算机,是Java语言的运行环境)允许应用程序并发地运行多个线程。在Java语言中,多线程的实现一般有以下三种方法:
(1) 实现 Runnable 接口,并实现该接口的 run() 方法;
① 自定义类并实现 Runnable 接口,实现 run() 方法。
② 创建 Thread 对象,用实现 Runnable 接口的对象作为参数实例化该 Thread 对象。
③ 调用 Thread 的 start() 方法。
// 创建线程类
class MyThread implements Runnable{
public void run(){
System.out.println("Thread body ..."); // 线程方法体
}
}
public class Test{
public static void main(String args[]){
MyThread thread = new MyThread();
Thread th = new Thread(thread);
th.start(); // 开启线程
}
}
(2) 继承 Thread 类,重写 run() 方法;
Thread本质上也是实现了 Runnable 接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过 Thread 类的 start()方法。start()方法是一个 native(本地) 方法,它将启动一个新线程,并执行 run() 方法(Thread中提供的 run() 方法是一个空方法)。这种方式通过自定义类直接 extends Thread,并重写 run() 方法,就可以启动新线程并执行自己定义的 run() 方法。需要注意的是,当 start() 方法调用后,并不是立即执行多线程代码,而是使得该线程变为可运行状态 (Runnable),至于什么时候运行多线程代码,是由操作系统决定的。
如下所示是 Thread 的使用方法:
// 创建线程类
class MyThread extends Thread{
public void run(){
System.out.println("Thread body ..."); // 线程的方法体
}
}
public class Test{
public static void main(String args[]){
MyThread thread = new MyThread();
thread.start(); // 开启线程
}
}
(3) 实现 Callable 接口,重写 call() 方法;
Callable 对象实际是属于 Executor 框架中的功能类,Callable 接口与 Runnable接口类似,但是提供了比 Runnable 更强大的功能,主要表现为以下三点:
① Callable 可以在任务结束后提供一个返回值,Runnable 无法提供这个功能;
② Callable 中的 call() 方法可以抛出异常,而 Runnable 的 run() 方法不能抛出异常;
③ 运行 Callable 可以拿到一个 Future 对象,Future对象表示异步计算的结果。它提供了检查计算是否完成的方法。由于线程属于异步计算模型,所以无法从其他线程中得到方法的返回值,在这种情况下,就可以使用 Future 来监视目标线程调用 call()方法的情况,当调用 Future 的 get()方法以获取结果时,当前线程就会阻塞,直到 call() 方法结束返回结果。
示例代码如下:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableAndFuture {
// 创建线程类
public static class CallableTest implements Callable<String>{
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "Hello World !!!";
}
}
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future<String> future = threadPool.submit(new CallableTest()); //启动线程
try {
System.out.println("waiting thread to finish !!!");
System.out.println(future.get()); //等待线程结束,并获取返回结果
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
以上程序运行结果如下所示:
在以上三种方式中,前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。当需要实现多线程时,一般推荐实现 Runnable 接口的方式,原因如下:首先,Thread 类定义了多种方法可以被派生类使用或重写,但是只有 run() 方法是必须被重写的,在 run() 方法中实现这个线程的主要功能。这当然是实现 Runnable 接口所需的同样的方法。而且,很多Java开发者认为,一个类仅在它们需要被加强或修改时才会被继承。因此,如果没有必要重写 Thread 类中的其他方法,那么通过继承 Thread 的实现方式与实现 Runnable 接口的效果相同,在这种情况下最好通过实现 Runnable 接口的方式来创建线程。