前言
我们先来了解下同步、异步有什么区别?
同步(Sync)
所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。
根据这个定义,Java中所有方法都是同步调用,应为必须要等到结果后才会继续执行。我们在说同步、异步的时候,一般而言是特指那些需要其他端协作或者需要一定时间完成的任务。
简单来说,同步就是必须一件一件事做,等前一件做完了才能做下一件事。
异步(Async)
异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。
对于通知调用者的三种方式,具体如下:
情况 | 作用 |
---|---|
状态 | 即监听被调用者的状态(轮询),调用者需要每隔一定时间检查一次,效率会很低。 |
通知 | 当被调用者执行完成后,发出通知告知调用者,无需消耗太多性能。 |
回调 | 与通知类似,当被调用者执行完成后,会调用调用者提供的回调函数。 |
FutureTask概念
FutureTask一个可取消的异步计算
,FutureTask 实现了Future的基本方法,可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后
获取,get方法会阻塞
当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消。
一个FutureTask 可以用来包装一个 Callable 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以一个 FutureTask可以提交(submit)给一个Excutor执行(excution).
FutureTask使用场景
FutureTask可用于异步
获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时
的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。
FutureTask执行多任务计算的使用场景
利用FutureTask和ExecutorService,可以用多线程的方式提交计算任务,主线程继续执行其他任务,当主线程需要子线程的计算结果时,在异步获取子线程的执行结果。
这里写了一个小demo直接上代码:
package com.silin;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class Test03 {
public static ExecutorService executor = Executors.newSingleThreadExecutor(); //创建一个线程池
public static long start = System.currentTimeMillis(); //获取执行到这行代码的系统时间
public static boolean flag = false; //定义个标识
public static int time = 5000; //定义方法的消耗时间
public static int timeout = 2000; //定义超时的时间
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
String result = timeoutMethod(timeout); //调用timeoutMethod(timeout)方法,并传一个实参
System.out.println("整个方法实际耗时:" + (System.currentTimeMillis() - start) + "毫秒"); //打印执行完timeoutMethod(timeout)的方法时间
System.out.println("结果:" + result);
}catch(Exception e){
e.printStackTrace();
System.out.println("异常");
}
}
/**
* 有超时时间的方法
* @param timeout
* @return
*/
private static String timeoutMethod(int timeout) throws Exception{
String result = "false";
FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() { //一个可取消的异步计算。该类提供了一个基类
@Override
public String call() throws Exception {
//TODO
boolean bool = unknowMethod(time); //调用unkonwMethod(time)方法
return "false";
}
});
executor.execute(futureTask); //池化线程或调用中执行futureTask
try {
result = futureTask.get(timeout, TimeUnit.MILLISECONDS); //这个方法会阻塞,直到任务完成时会返回
} catch (InterruptedException | ExecutionException | TimeoutException e) {
//e.printStackTrace();
flag = true;
futureTask.cancel(true); // 为false时,会等待这个任务执行完,返回true;若任务还没执行,取消任务后返回true,如任务执行完,返回false
result = "false";
System.out.println("方法实际执行时间:" + (System.currentTimeMillis() - start) + "毫秒");
executor.shutdown();
}
return result;
}
/**
* 这个方法的耗时
* @return
*/
private static boolean unknowMethod (int time) throws Exception{
if(flag){
Thread.sleep(time);
System.out.println("任务需要耗时: " + time + "毫秒" + "___标志" + flag);
}else{
System.out.println("不执行");
}
return flag;
}
}
FeatureTast部分方法:
情况 | 作用 |
---|---|
report(int s) |
返回已完成任务的结果或引发异常。 |
isCancelled() |
判断task是否在正常完成前取消掉了。 |
isDone() |
返回ture或false |
cancel(boolean mayInterruptIfRunning) |
取消task的执行,如果task已完成、已被取消、或者由于某些原因取消不了,则返回false |
get() |
等待task完成,并获取执行结果。可能会抛出异常 |
get(long timeout, TimeUnit unit) |
在指定的时间内等待task完成,并获取执行结果。可能抛出异常(含TimeoutException) |
总结:
通过一个小小的demo,进行修改,改成小伙伴所需的。
如果写的不好,还请小伙伴多多批评指正。