一、背景
1.为了提高业务上面的时间,以及程序的效率,最终使用了多线程。我选用的是callable来实现的多线程。下面我就用简单的小栗子来说下吧。
二、callable简介
1.在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。
2.Java中,也提供了使用Callable和Future来实现获取任务结果的操作。Callable用来执行任务,产生结果,而Future用来获得结果。
3.Callable接口与Runnable接口是否相似,查看源码,可知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接口不同之处在于,call方法带有泛型返回值V。
三、小栗子
1.代码
public class Test0002 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> submit = executorService.submit(new TaskCallable());
System.out.println("执行任务开始(主线程)。。。");
String result = submit.get();
System.out.println(result);
System.out.println("执行任务结束(主线程)。。。");
}
static class TaskCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("执行任务开始(子线程)。。。");
Thread.sleep(5000);
System.out.println("执行任务结束(子线程)。。。");
return "chenmingxu";
}
}
}
2.结果
执行任务开始(主线程)。。。
执行任务开始(子线程)。。。
执行任务结束(子线程)。。。
chenmingxu
执行任务结束(主线程)。。。
3.分析
3.1.submit.get()是在主程序中,在它之前程序是不会进行阻塞的,但是在它之后程序会发生阻塞,只有拿到所有的结果后,主程序才会开始执行。
3.2.这样我们就可以单独开一个线程来单独把获取结果的代码提取出来,这样就可以提高程序的执行效率并且与主线程互不影响。
4.future的常用方法
V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCanceller() :如果任务完成前被取消,则返回true。
boolean cancel(boolean mayInterruptRunning) :如果任务还没开始,执行cancel(...)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(...)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。
通过方法分析我们也知道实际上Future提供了3种功能:(1)能够中断执行中的任务(2)判断任务是否执行完成(3)获取任务执行完成后额结果。
四、实例
1.代码
public class Test0002 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> submit = executorService.submit(new TaskCallable());
System.out.println("执行任务开始(主线程)。。。");
new Thread(new Runnable() {
@Override
public void run() {
String result = null;
try {
result = submit.get();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(result);
}
}).start();
System.out.println("执行任务结束(主线程)。。。");
executorService.shutdown();
}
static class TaskCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("执行任务开始(子线程)。。。");
String name = "chenmingxu";
System.out.println("执行任务结束(子线程)。。。");
return testDemo(name);
}
private String testDemo(String name) throws InterruptedException {
Thread.sleep(5000);
return name;
}
}
}
2.结果
执行任务开始(主线程)。。。
执行任务开始(子线程)。。。
执行任务结束(子线程)。。。
执行任务结束(主线程)。。。
chenmingxu
3.分析
3.1.我们可以从执行结果上面看到我们的主线程以及和子线程执行是互相不影响的。
五、结束
1.Always keep the faith!!!