有的时候我们需要同时执行两个任务,但是任务A需要等待任务B的结果才能继续执行,如果在一般情况下,我们需要先等待B执行完毕再执行A,这样串行执行比较耗费时间,总耗时就是B的时间+A的时间。
long start = System.currentTimeMillis();
//执行任务A
System.out.println("开始执行A任务");
Thread.sleep(2000);
System.out.println("A任务前半部分执行完毕");
System.out.println("开始执行B任务");
int a = 1+1;
Thread.sleep(2000);
System.out.println("B任务执行完毕");
System.out.println("获取B任务返回结果:"+a);
System.out.println("A任务继续执行后半部分");
Thread.sleep(2000);
System.out.println("A任务执行完毕");
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
总耗时大约为6秒多,代码执行过程如下所示:
如果我们能够让A和B分两个线程执行,A把不依赖B的部分先执行完,然后接收B返回的结果,最后A再执行剩余部分,这样的话,执行时间就会缩短很多。
Java创建线程通常使用继承Thread或实现Runnable然后重写run方法来实现,这两种方式的线程都是没有返回值的,只能通过共享内存变量来进行参数传递,如果我们想知道线程的处理结果,需要通过轮询等方式实现,比较麻烦。
Java1.5之后新增了第三种方式,使用Callable接口和FutureTask创建任务,指定的泛型是你需要的返回值类型,下面代码里需要返回加法计算的结果,所以返回值的泛型是Integer,然后再用Thread构造线程。最后通过调用futureTask的get()方法获取返回结果。如果调用这个方法的时候线程还没处理完,那么将会等待结果之后再执行之后的代码。
long start = System.currentTimeMillis();
//创建一个单独的线程执行任务B
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("开始执行B任务");
int a = 1+1;
Thread.sleep(2000);
System.out.println("B任务执行完毕");
return a;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
//主线程执行任务A
System.out.println("开始执行A任务");
Thread.sleep(2000);
System.out.println("A任务前半部分执行完毕");
System.out.println("获取B任务返回结果:"+futureTask.get());
System.out.println("A任务继续执行后半部分");
Thread.sleep(2000);
System.out.println("A任务执行完毕");
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
这样可以让执行时间缩短到4秒,节约了等待B执行的部分时间
代码将会以下面的方式执行:
这样我们简单的了解了一下Java创建线程的第三种方式。