1.Runnable
(1).缺陷
- 没有返回值
- 不能抛出一个检查异常
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
(2).解决方案Callable
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
2.Future
(1).作用
Future是一个存储器,它存储了Callable这个任务的执行结果,而这个任务的执行时间无法提前确定,取决于call()方法的执行情况。
(2).isDone()
判断线程是否执行完毕,但并不能保证任务是否成功被执行。
(3).get()
get()方法的行为取决于Callable任务的状态,该状态有以下5种情况。
- 任务正常完成
get()方法会立刻获取任务的执行结果。
public class OneFuture {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
Future<Integer> future = service.submit(new CallableTask());
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
service.shutdown();
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
return new Random().nextInt();
}
}
}
public class MultiFutures {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(20);
ArrayList<Future> futures = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Future<Integer> future = service.submit(new CallableTask());
futures.add(future);
}
Thread.sleep(5000);
for (int i = 0; i < 20; i++) {
Future<Integer> future = futures.get(i);
try {
Integer integer = future.get();
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(3000);
return new Random().nextInt();
}
}
}
- 任务尚未完成()
get()方法会阻塞,直到任务完成。 - 任务执行过程中抛出Exception
get()方法会抛出ExecutionException。
public class GetException {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(20);
Future<Integer> future = service.submit(new CallableTask());
try {
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException异常");
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("ExecutionException异常");
}
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() {
throw new IllegalArgumentException("Callable抛出异常");
}
}
}
public class GetException {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(20);
Future<Integer> future = service.submit(new CallableTask());
try {
//for循环为了演示抛出Exception的时机:并不是说一产生异常就抛出,直到我们get执行时,才会抛出。
for (int i = 0; i < 5; i++) {
System.out.println(i);
Thread.sleep(500);
}
System.out.println(future.isDone());
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException异常");
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("ExecutionException异常");
}
}
static class CallableTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
throw new IllegalArgumentException("Callable抛出异常");
}
}
}
- 任务被取消
get方法会抛出CancellationException。 - 任务超时
get()方法有一个重载方法,是传入一个延时时间的,如果在参数时间内没有获得结果,get()方法就会抛出TimeoutException。超时不需要时,要通知任务,取消任务。
(4).cancel()
取消任务的执行。
public class Timeout {
private static final Ad DEFAULT_AD = new Ad("无网络时候的默认广告");
private static final ExecutorService executorService = 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<Ad> {
@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<Ad> future = executorService.submit(new FetchAdTask());
Ad ad;
try {
ad = future.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("超时,未获取到广告");
//传入true和false的区别,代表是否中断正在执行的任务
boolean cancel = future.cancel(true);
System.out.println("cancel的结果:" + cancel);
}
executorService.shutdown();
System.out.println(ad);
}
public static void main(String[] args) {
Timeout timeout = new Timeout();
timeout.printAd();
}
}
(5).isCanceled()
判断任务是否被取消。
3.FutureTask
(1).FutureTask家族成员
public class FutureTaskDemo {
public static void main(String[] args) {
Task task = new Task();
FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
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<Integer> {
@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;
}
}
4.卖票案例
public class SellTicket implements Callable {
ReentrantLock lock = new ReentrantLock();
private Integer number = 1000;
@Override
public Object call() throws Exception {
while (number > 0) {
try {
lock.lock();
//双重检查
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "sell ticket " + number--);
}
} finally {
lock.unlock();
}
}
return number;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(5);
SellTicket sellTicket = new SellTicket();
List<Future<Integer>> futureList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
futureList.add(executorService.submit(sellTicket));
}
//让子线程执行完任务
Thread.sleep(1000);
for (int i = 0; i < futureList.size(); i++) {
int finalNumber = futureList.get(i).get();
System.out.println("finalNumber:" + finalNumber);
}
executorService.shutdown();
}
}