Future和Callable
Callable和Runnable主要區別爲:
- Callable接口的call)方法可以有返回值,而Runnable接口的run()方法沒有返回值。
- Callable 接口的call0)方法可以聲明拋出異常,而Runnable接口的run()方法不可以聲明拋出異常。
執行完Callable接口中的任務後,返回值是通過Future 接口進行獲得的。
get()和ExecutorService中的submit()和isDone()的使用
方法submit()不僅可以傳人Callable對象,也可以傳人Runnable對象,說明submit()方法支持有返回值和無返回值的功能。
public class TestDemo {
public static void main(String[] args) {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "返回值";
}
};
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(callable);
System.out.println(future.isDone());
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
get()方法具有阻塞性,而isDone()方法無阻塞性。
cancel(boolean mayInterruptIfRunning)和isCancelled()的使用
- 方法cancel(boolean mayInterruptIfRunning)的參數mayInterruptIfRunning的作用是:如果線程正在運行則是否中斷正在運行的線程,在代碼中需要使用
if(Thread.currentThreadO.islnterrupted()
進行配合。 - 方法cancel()的返回值代表發送取消任務的命令是否成功完成。
public class TestDemo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "我的年齡是100";
}
};
ExecutorService executorService = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5,
TimeUnit.SECONDS, new LinkedBlockingDeque<>());
Future<String> future = executorService.submit(callable);
System.out.println(future.get());
System.out.println(future.cancel(true) + " " + future.isCancelled());
}
}
從打印的結果來看,線程任務已經運行完畢,線程對象已經銷燬,所以方法cancel()的返回值是false,代表發送取消的命令並沒有成功。
public class TestDemo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "我的年齡是100";
}
};
ExecutorService executorService = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5,
TimeUnit.SECONDS, new LinkedBlockingDeque<>());
Future<String> future = executorService.submit(callable);
System.out.println(future.cancel(true) + " " + future.isCancelled());
}
}
任務在沒有運行完成之前執行了cancel()方法返回爲true,代表成功發送取消的命令。
結合if(Thread.currentThread().isInterrupted())中斷線程:
public class TestDemo3 {
public static void main(String[] args) throws InterruptedException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
int i = 0;
while (i == 0) {
if (Thread.currentThread().isInterrupted())
throw new InterruptedException();
System.out.println("正在運行中");
}
return "返回值";
}
};
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(callable);
Thread.sleep(3000);
System.out.println(future.cancel(true) + " " + future.isCancelled());
}
}
線程中斷成功。
如果cacnel()傳入false,則線程不中斷。
get(long timeout, TimeUnit unit):
方法get(long timeout, TimeUnit unit) 的作用是在指定的最大時間內等待獲得返回值。
execute()和submit()的區別
- 方法execute()沒有返回值,而submit()方法可以有返回值。
- 方法execute()在默認的情況下異常直接拋出,不能捕獲,但可以通過自定義ThreadFactory的方式進行捕獲,而submit()方法在默認的情況下,可以try-catch捕獲異常。
execute()出現異常後直接打印堆棧信息:
public class TestDemo4 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
Integer.parseInt("xxx");
});
}
}
submit()方法可以捕獲異常:
public class TestDemo4 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(() -> {
Integer.parseInt("xxx");
return "返回值";
});
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("能捕獲異常");
}
}
}
execute()方法通過ThreadFactory捕獲異常:
public class TestDemo5 {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 10, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("executor()方法通過使用自定義");
System.out.println("ThreadFactory也能捕獲異常");
e.printStackTrace();
}
});
return t;
}
});
pool.execute(() -> {
Integer.parseInt("xxx");
});
System.out.println("main end");
}
}