Java 提供了三种创建线程的方法
- 通过实现Runnable接口
- 通过继承Thread接口
- 通过Callable和Future创建线程
通过实现 Runnable 接口来创建线程
public class RunnableDemo { public static void main(String[] args) { new Thread(new MyThread(),"线程1").start(); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } },"线程2").start(); } } /** * 实现 Runnable 接口的线程类 */ class MyThread implements Runnable{ /** * 重写run方法 */ @Override public void run() { // TODO Auto-generated method stub } }
通过继承Thread类
public class ThreadDemo { public static void main(String[] args) { new MyThread().start(); new Thread(new MyThread(), "线程2").start(); } } class MyThread extends Thread{ /** * 重写run方法 */ @Override public void run() { // TODO Auto-generated method stub super.run(); } }
通过Callable和Future创建线程
public class FutureDemo { public static void main(String[] args) { //创建 Callable 实现类的实例 MyCallable myCallable = new MyCallable(); //使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值 FutureTask<String> futureTask = new FutureTask<String>(myCallable); String res = null; try { //使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程 //没这句,下句代码获取不到结果,会一直等待执行结果 new Thread(futureTask,"线程1").start(); //调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值 res = futureTask.get(); } catch (Exception e) { e.printStackTrace(); } System.out.println(res); } } /** * 创建 Callable 接口的实现类,并实现 call() 方法 */ class MyCallable implements Callable<String>{ /** * 该 call() 方法将作为线程执行体,并且有返回值 */ @Override public String call() throws Exception { return "success"; } }
Runnable和Callable的异同:
相同点:
- 两者都是接口;(废话)
- 两者都可用来编写多线程程序;
- 两者都需要调用Thread.start()启动线程;
不同点:
- 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
- Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;
注意点:
- Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!
Callable的优势
多线程返回执行结果是很有用的一个特性,因为多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候我们期望的数据是否已经赋值完毕?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却可以获取多线程运行的结果,可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务,真的是非常有用。