建设银行官方网站官网,电商在线官方,做菠菜网站代理,外包服务有哪些一、为啥要引入Callable
在前面讲了通过继承Thread和实现Runnable方式创建线程的区别#xff0c;那为什么有了Runnable还要引入Callable?下面通过实现Runnable方式的弊端给出答案
实现Runnable方式的弊端#xff1a;
package java.lang;
FunctionalInterface
public inte…一、为啥要引入Callable
在前面讲了通过继承Thread和实现Runnable方式创建线程的区别那为什么有了Runnable还要引入Callable?下面通过实现Runnable方式的弊端给出答案
实现Runnable方式的弊端
package java.lang;
FunctionalInterface
public interface Runnable {public abstract void run();
}package java.util.concurrent;
FunctionalInterface
public interface CallableV {V call() throws Exception;
}通过上面两个接口的定义可以看出
1、实现Runnable的方式没有返回值
2、实现Runnable的方式无法抛出异常
注实现Callable方式是JDK1.5引入的
二、如何通过实现Callable方式创建线程
如何创建
这种方式创建线程需要配合FutureTask或者线程池来实现下面给出通过配合FutureTask来创建线程的代码
public static void main(String[] args) {//1、定义一个Callable任务CallableString task new CallableString() {Overridepublic String call() throws Exception {System.out.println(任务正在执行Thread.currentThread().getName());return OK;}};//2、创建FutureTask对象,传入刚创建的taskFutureTaskString futureTask new FutureTask(task);//3、创建线程并执行FutureTaskThread thread new Thread(futureTask);thread.start();}运行结果 如何获取返回值
通过FutureTask的get方法可以获取返回值
public static void main(String[] args) {//1、定义一个Callable任务CallableString task new CallableString() {Overridepublic String call() throws Exception {System.out.println(任务正在执行Thread.currentThread().getName());return OK;//返回一个值}};//2、创建FutureTask对象,传入刚创建的taskFutureTaskString futureTask new FutureTask(task);//3、创建线程并执行FutureTaskThread thread new Thread(futureTask);thread.start();//4、获取返回值try {String result futureTask.get();System.out.println(返回值result);} catch (Exception e) {throw new RuntimeException(e);}}执行结果 因为call方法可能会抛出异常所以需要使用try…catch捕获
取消当前线程
FutureTask.java
public boolean cancel(boolean mayInterruptIfRunning) {if (!(state NEW UNSAFE.compareAndSwapInt(this, stateOffset, NEW,mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))return false;try { // in case call to interrupt throws exceptionif (mayInterruptIfRunning) {try {Thread t runner;if (t ! null)t.interrupt();} finally { // final stateUNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);}}} finally {finishCompletion();}return true;
}FutureTask类中提供了一个cancel方法用于取消当前线程下面是使用实例
public static void main(String[] args) {//1、定义一个Callable任务CallableString task new CallableString() {Overridepublic String call() throws Exception {try {for (int i 0; i 10; i) {System.out.println(Task running... i);Thread.sleep(1000); // 模拟任务的执行}return OK;} catch (InterruptedException e) {System.out.println(Task was interrupted);throw e;}}};//2、创建FutureTask对象,传入刚创建的taskFutureTaskString futureTask new FutureTask(task);//3、创建线程并执行FutureTaskThread thread new Thread(futureTask);thread.start();try {// 主线程等待 3 秒钟然后取消任务Thread.sleep(3000);System.out.println(Cancelling the task...);futureTask.cancel(true); // 取消任务并设置为允许中断线程// 检查任务是否被取消if (futureTask.isCancelled()) {System.out.println(Task was cancelled);} else {// 尝试获取任务结果这行代码可能永远不会执行因为任务已经被取消String result futureTask.get();System.out.println(Task result: result);}} catch (Exception e) {e.printStackTrace();}}执行结果 注实现Runnable创建线程的方式是没有cancel方法来取消当前任务的
三、配合线程池一起使用
public static void main(String[] args) {// 创建一个固定线程池ExecutorService executorService Executors.newFixedThreadPool(3);// 定义一个 Callable 任务CallableString task new CallableString() {Overridepublic String call() throws Exception {if (Math.random() 0.5) {throw new RuntimeException(Random failure occurred);}return Task completed successfully;}};// 提交任务给线程池并获取 Future 对象FutureString future executorService.submit(task);try {// 获取任务的结果String result future.get();System.out.println(Result: result);} catch (InterruptedException e) {// 线程被中断时的处理e.printStackTrace();} catch (ExecutionException e) {// call 方法抛出的异常会被封装在 ExecutionException 中Throwable cause e.getCause();if (cause instanceof Exception) {// 处理 call 方法抛出的异常System.err.println(Exception caught: cause.getMessage());}}// 关闭线程池executorService.shutdown();}执行结果 当call方法中Math.random() 0.5成立时执行结果为
四、总结
1、实现Callable的方式有返回值
2、实现Callable的方式可以抛出异常
3、实现Callable的方式可以通过FutureTask类中提供了一个cancel方法取消任务