Java多线程实现方式主要有四种:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。
其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。
Runnable和Callable的区别
Runnable接口
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
Callable接口
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Runnable和Callable的区别
1.Runnable执行方法是run(),Callable是call()
2.实现Runnable接口的任务线程无返回值;实现Callable接口的任务线程能返回执行结果
3.call方法可以抛出异常,run方法若有异常只能在内部消化
注意
Callable接口支持返回执行结果,需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取结果;当不调用此方法时,主线程不会阻塞!
如果线程出现异常,Future.get()会抛出throws InterruptedException或者ExecutionException;如果线程已经取消,会爬出CancellationException
Callable示例
package com.keda.activiti.config;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @program: xxx
* @description:
* @author: shuonar
* @create: 2020-06-02 16:52
**/
public class ExecutorsTest {
public static void main(String[] args) {
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 thread ....");
Future<String> future = executorService.submit(callable);
try {
System.out.println("future.get()=" + future.get());
}catch (Exception e){
e.printStackTrace();
}
System.out.println("end thread...");
// 切记:关闭线程池
executorService.shutdown();
}
}
start thread ....
Thread_current=Thread[pool-1-thread-1,5,main]
future.get()=Hello World!
end thread...
其它
在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
1.避免点继承的局限,一个类可以实现多个接口
2.资源共享
Runnable接口和Thread之间的联系
public class Thread extends Object implements Runnable
由此可见:Thread类也是Runnable接口的子类