java中实现Callable方式创建线程

一、为啥要引入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 Callable<V> {
    
    
    V call() throws Exception;
}

通过上面两个接口的定义可以看出

1、实现Runnable的方式没有返回值

2、实现Runnable的方式无法抛出异常

注:实现Callable方式是JDK1.5引入的

二、如何通过实现Callable方式创建线程

如何创建

这种方式创建线程需要配合FutureTask或者线程池来实现,下面给出通过配合FutureTask来创建线程的代码

public static void main(String[] args) {
    
    
        //1、定义一个Callable任务
        Callable<String> task = new Callable<String>() {
    
    
            @Override
            public String call() throws Exception {
    
    
                System.out.println("任务正在执行"+Thread.currentThread().getName());
                return "OK";
            }
        };
        //2、创建FutureTask对象,传入刚创建的task
        FutureTask<String> futureTask = new FutureTask<>(task);
        //3、创建线程并执行FutureTask
        Thread thread = new Thread(futureTask);
        thread.start();
    }

运行结果:
在这里插入图片描述
如何获取返回值

通过FutureTask的get方法可以获取返回值

public static void main(String[] args) {
    
    
        //1、定义一个Callable任务
        Callable<String> task = new Callable<String>() {
    
    
            @Override
            public String call() throws Exception {
    
    
                System.out.println("任务正在执行"+Thread.currentThread().getName());
                return "OK";//返回一个值
            }
        };
        //2、创建FutureTask对象,传入刚创建的task
        FutureTask<String> futureTask = new FutureTask<>(task);
        //3、创建线程并执行FutureTask
        Thread 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捕获

扫描二维码关注公众号,回复: 17439702 查看本文章

取消当前线程

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 exception
        if (mayInterruptIfRunning) {
    
    
            try {
    
    
                Thread t = runner;
                if (t != null)
                    t.interrupt();
            } finally {
    
     // final state
                UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
            }
        }
    } finally {
    
    
        finishCompletion();
    }
    return true;
}

FutureTask类中提供了一个cancel方法用于取消当前线程,下面是使用实例

public static void main(String[] args) {
    
    
        //1、定义一个Callable任务
        Callable<String> task = new Callable<String>() {
    
    
            @Override
            public 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对象,传入刚创建的task
        FutureTask<String> futureTask = new FutureTask<>(task);
        //3、创建线程并执行FutureTask
        Thread 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 任务
        Callable<String> task = new Callable<String>() {
    
    
            @Override
            public String call() throws Exception {
    
    
                if (Math.random() > 0.5) {
    
    
                    throw new RuntimeException("Random failure occurred");
                }
                return "Task completed successfully";
            }
        };

        // 提交任务给线程池并获取 Future 对象
        Future<String> 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方法取消任务

猜你喜欢

转载自blog.csdn.net/weixin_40323532/article/details/139886740