创建线程的四种方式
Java多线程实现方式主要有四种:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。
其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。
Runnable和Callable的区别
Runnable接口
public interface Runnable {
void run();
}
Callable接口
public interface Callable<V> {
V call() throws Exception;
}
Runnable和Callable的区别
- Runnable执行方法是run(),Callable是call()
- 实现Runnable接口的任务线程无返回值;实现Callable接口的任务线程能返回执行结果
- call方法可以抛出异常,run方法若有异常只能在内部消化
注意
Callable接口支持返回执行结果,需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取结果;当不调用此方法时,主线程不会阻塞!
如果线程出现异常,Future.get()会抛出throws InterruptedException或者ExecutionException;如果线程已经取消,会爬出CancellationException
Callable示例
public class CallableDemo {
public static void main(String[] args) {
//创建一个定长的核心线程和最大线程数都是1的FixedThreadPool线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("Thread_current="+Thread.currentThread());
return "Hello world";
}
};
System.out.println("start");
// 执行任务并获取Future对象
Future<String> future = executorService.submit(callable);
try{
//future.get()线程结果,会阻塞当前线程直到线程结束
System.out.println("future.get()="+future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("end");
// 关闭线程池
executorService.shutdown();
}
}
其它
在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
- 避免点继承的局限,一个类可以实现多个接口
- 资源共享
Runnable接口和Thread之间的联系
public class Thread extends Object implements Runnable
由此可见:Thread类也是Runnable接口的子类