前言
多线程的实现一般有3中方法,其中前两种最常用。
1.继承Thread类,重写run方法
Thread类从本质上来讲,也是实现Runnable接口的一个实例。调用start()方法后只是会使线程处于可运行状态,并不会立即执行多线程代码。至于多线程代码何时运行,有操作系统决定。
步骤:
a.定义Thread类的子类,重写run()方法,run方法体代表了线程要完成的任务。所以run方法也被称为执行体
b.创建Thread子类的实例,即代表创建线程对象
c.调用线程对象的start()方法来启动线程
public class TestThread extends Thread {
@Override
public void run() {
System.out.println("hello world!");
}
public static void main(String []args){
TestThread thread = new TestThread();
thread.start();
}
}
2.实现Runnable接口,并实现run方法
a.自定义类实现Runnable接口,并实现run方法
b.创建Thread子类实例,用 实现Runnable接口的对象 作为参数实例化该Thread对象
c.调用start方法启动
public class TestRunnable implements Runnable {
@Override
public void run() {
System.out.println("hello world!");
}
public static void main(String []args){
TestRunnable runnable = new TestRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
3.实现callable接口,重写call方法
Callable接口实际是属于Executor框架中的功能类,与Runnable接口的功能相似,但提供了比Runnable更强大的功能:
a.Callable可以在任务结束后可以提供一个返回值,Runnable就不行了
b.call()方法可以抛出异常,run方法不可以
c.运行Callable可以拿到一个Future对象,它表示异步计算的结果,提供了检查计算是否完成的方法。因为线程属于异步计算模型,无法从其他线程中获取返回值,此时就可以使用Future来监视目标线程调用call()的情况。但是Future的get()获取结果时,当前线程就会发生阻塞,直到call()返回结果。
public class TestCallable {
//创建Callable接口实现类,重写call方法
public static class MyTestCallable implements Callable{
@Override
public Object call() throws Exception {
return "hello world!";
}
}
public static void main(String []args){
//创建Callable实例
MyTestCallable myTestCallable = new MyTestCallable();
ExecutorService service = Executors.newSingleThreadExecutor();//单线程化的线程池
Future future = service.submit(myTestCallable);
try {
//等待线程结束并返回结果
System.out.println(future.get());
}catch (Exception e){
e.printStackTrace();
}
}
}
总结
上述3中方式,推荐使用实现Runnable接口的方式。因为一个类应该在需要加强、修改的时候才会被继承,没必要重写Thread类的其他方法。显然,Runnable接口是最好的选择。