1.大纲
Runnable的不足
CallAble的接口
Future类
一:Runnable的不足
1.不足
不能返回返回值
run方法不能抛出异常,因为大部分可以处理异常的不是我们写的,所以,要想处理,还是要在run里进行自己处理异常
2.程序
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface Runnable
is used
* to create a thread, starting the thread causes the object's
* run
method to be called in that separately executing
* thread.
*
* The general contract of the method run
is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
二:CallAble接口
1.说明
实现call
2.程序
@FunctionalInterface
public interface Callable {
/**
* 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;
}
三:Future
1.作用
不要要等待,需要的时候,到future获取数据
2.Callable与Future的关系
可以使用Future.get来获取Callable接口返回的执行结果
可以通过Future.isDone来判断任务是否已经执行完成,
如果call()还没有执行完成,调用get的线程将会被阻塞,只有等运行完成,才能获取到结果,然后主线程才回切换到runnable的状态
3.总结
Future是一个存储器,存储了call这个任务的结果
4.主要方法
5.get方法
V get() throws InterruptedException, ExecutionException;
6.get(timeout,unit)
V get(long timeout, TimeUnit unit)
超时很常见
超时不获取,任务需要取消
7.cancel方法
boolean cancel(boolean mayInterruptIfRunning);
8.isDone
boolean isDone();
是否完毕,不一定是成功的,抛出异常也是执行完毕
9.isCancel
boolean isCancelled();
四:代码演示
1.基础的用法
线程池的submit方法返回Future对象
public class OneFuture {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
Future future = executorService.submit(new CallableTask());
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
}
static class CallableTask implements Callable{
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
return new Random(10).nextInt();
}
}
}
效果:
Connected to the target VM, address: '127.0.0.1:49767', transport: 'socket'
-1157793070
Disconnected from the target VM, address: '127.0.0.1:49767', transport: 'socket'
Process finished with exit code 0
2.lambda方式
public class TwoFuture {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
Callable callable = ()->{
Thread.sleep(3000);
return new Random(10).nextInt();
};
Future future = executorService.submit(callable);
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
3.多个任务,使用Future数组来获取结果
package com.jun.juc.feature;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.*;
public class ThreeFuture {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Callable callable = ()->{
Thread.sleep(3000);
return new Random(10).nextInt();
};
ArrayList futures = new ArrayList<>();
for(int i=0;i<20;i++){
Future future = executorService.submit(callable);
futures.add(future);
}
//
for(int i=0;i<20;i++){
Future future = futures.get(i);
try {
Integer integer = future.get();
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
结果:
可以发现,每次是两个结果返回。因为线程池中才两个线程。
4.任务执行过程中抛出异常
package com.jun.juc.feature;
import java.util.Random;
import java.util.concurrent.*;
public class FourFuture {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
Callable callable = ()->{
throw new IllegalArgumentException("callable异常");
};
Future future = executorService.submit(callable);
try {
Thread.sleep(5000);
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException异常了");
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("ExecutionException异常了");
}
executorService.shutdown();
}
}
只有在get的时候,才会抛出异常,而且异常是ExecutionException
5.获取任务超时
package com.jun.juc.feature;
import java.util.concurrent.*;
public class FiveFuture {
private static final Ad DEFAULT_AD = new Ad("无网络时候的默认广告");
private static final ExecutorService exec = Executors.newFixedThreadPool(10);
static class Ad {
String name;
public Ad(String name) {
this.name = name;
}
@Override
public String toString() {
return "Ad{" +
"name='" + name + '\'' +
'}';
}
}
static class FetchAdTask implements Callable {
@Override
public Ad call() throws Exception {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
System.out.println("sleep期间被中断了");
return new Ad("被中断时候的默认广告");
}
return new Ad("旅游订票哪家强?找某程");
}
}
public void printAd() {
Future f = exec.submit(new FetchAdTask());
Ad ad;
try {
ad = f.get(2000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
ad = new Ad("被中断时候的默认广告");
} catch (ExecutionException e) {
ad = new Ad("异常时候的默认广告");
} catch (TimeoutException e) {
ad = new Ad("超时时候的默认广告");
System.out.println("超时,未获取到广告");
boolean cancel = f.cancel(true);
System.out.println("cancel的结果:" + cancel);
}
exec.shutdown();
System.out.println(ad);
}
public static void main(String[] args) {
FiveFuture timeout = new FiveFuture();
timeout.printAd();
}
}
运行结果:
Disconnected from the target VM, address: '127.0.0.1:55224', transport: 'socket'
超时,未获取到广告
sleep期间被中断了
cancel的结果:true
Ad{name='超时时候的默认广告'}
Process finished with exit code 0
说明:
cancel方法传入true,则运行的方法会抛出异常
6.calcel的说明
7.传入false的作用
如果任务没有开始,false传入,任务会被打上标记,然后任务不会被执行。
8.传入true还是false
true适用:
任务能够处理interrupt
false:
未能处理interrupt的任务
不清楚任务是否支持取消
五:FutureTask创建Future
1.结构
2.程序
package com.jun.juc.feature;
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;
/**
* 描述: 演示FutureTask的用法
*/
public class FutureTaskDemo {
public static void main(String[] args) {
Task task = new Task();
FutureTask integerFutureTask = new FutureTask<>(task);
// new Thread(integerFutureTask).start();
ExecutorService service = Executors.newCachedThreadPool();
service.submit(integerFutureTask);
try {
System.out.println("task运行结果:"+integerFutureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class Task implements Callable {
@Override
public Integer call() throws Exception {
System.out.println("子线程正在计算");
Thread.sleep(3000);
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}
}
效果:
Connected to the target VM, address: '127.0.0.1:55709', transport: 'socket'
子线程正在计算
task运行结果:4950
Disconnected from the target VM, address: '127.0.0.1:55709', transport: 'socket'
Process finished with exit code 1