Java: 模拟开启多个线程处理数据,完成数据处理后回到主线程,并return数据

工作中经常使用到线程池,那如何保证多个线程都执行完后回到主线程呢?其中某个线程异常该如何处理呢?

一、开启多线程 

在Java中,我们通常使用Thread类或者Runnable接口来创建线程。但是,直接使用Thread类或者Runnable接口的线程在完成任务后无法直接返回结果到主线程。这是因为线程一旦启动,其生命周期就不再受主线程控制,主线程无法直接获取子线程的返回值。

一种常见的解决办法是使用Callable接口和Future任务。Callable接口是一个泛型接口,它的call方法可以返回一个结果,并且可能抛出异常。ExecutorService可以提交一个Callable任务并返回一个Future对象,通过这个Future对象我们可以取消计算,检查是否完成,并且获取计算结果。

以下是一个简单的例子:

public static void testThread() throws ExecutionException, InterruptedException {
        long l = System.currentTimeMillis();
        // 创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 创建两个 Callable 任务
        Callable<String> task1 = new Callable<String>() {
            @Override
            public String call() throws Exception {
                // 进行一些耗时的计算
                Thread.sleep(6000);
                return "Result of Task 1";
            }
        };

        Callable<String> task2 = new Callable<String>() {
            @Override
            public String call() throws Exception {
                // 进行一些耗时的计算
                Thread.sleep(1000);
                return "Result of Task 2";
            }
        };

        // ## 方案一
        // 提交任务并获取 Future 对象
        Future<String> future1 = executor.submit(task1);
        Future<String> future2 = executor.submit(task2);

        // 在主线程中进行其他工作...

        // 获取任务结果
        String result1 = future1.get();
        String result2 = future2.get();

        // 关闭线程池
        executor.shutdown();

        // 输出结果
        System.out.println(result1);
        System.out.println(result2);


        // ## 方案二
        /*executor.submit(task1);
        executor.submit(task2);
        // 关闭线程池
        executor.shutdown();
        try {
            // 设置超时时间
            if (!executor.awaitTermination(2000, TimeUnit.MILLISECONDS)) {
                System.out.println("Tasks took too long to finish.");
            }
        } catch (InterruptedException e) {
            System.err.println("Interrupted while waiting for tasks to finish.");
        }*/



        System.out.println("耗时:" + (System.currentTimeMillis() - l) + "ms");
    }

在这个例子中,我们创建了两个Callable任务并提交给线程池执行。然后我们在主线程中进行其他工作,当需要的时候,我们通过Future对象获取任务的结果。注意,future1.get()future2.get()会阻塞直到对应的任务完成。

最后,记得关闭线程池。这将通知线程池停止接收新的任务,并且等待已经提交的任务完成。

二、ExecutorService类中的API有哪些

ExecutorService接口是java.util.concurrent包的一部分,它提供了一组方法来管理线程池。以下是一些主要的API方法:

  1. submit(Runnable task):提交一个Runnable任务到线程池,返回一个Future对象,可以用来取消任务或获取任务结果。

  2. <T> Future<T> submit(Callable<T> task):提交一个Callable任务到线程池,返回一个Future对象,可以用来取消任务或获取任务结果。

  3. ExecutorService execute(Runnable command):执行一个Runnable任务,但不返回Future对象,通常用于无返回值的任务。

  4. List<Future<?>> invokeAll(Collection<? extends Callable<V>> tasks):提交一组Callable任务,并等待所有任务完成,返回一个包含所有Future对象的列表。

  5. V invokeAny(Collection<? extends Callable<V>> tasks):提交一组Callable任务,并等待任何一个任务完成,返回该任务的结果。

  6. shutdown():平滑地关闭线程池,等待所有已提交的任务完成,不再接受新的任务。

  7. shutdownNow():立即停止所有正在执行的任务,并尝试停止所有未开始的任务,返回一个包含未执行任务的列表。

  8. isShutdown():检查线程池是否已经关闭。

  9. isTerminated():检查线程池是否已经终止,即所有任务都已经完成。

  10. awaitTermination(long timeout, TimeUnit unit):等待线程池终止,如果在指定时间内没有终止,则返回false。

三、此是多个线程是同步运行吗

在上述示例中,两个任务是并发运行的,而不是同步运行。当你调用executor.submit(task1)executor.submit(task2)时,这两个任务会被提交到线程池并且在线程池的可用线程上并发执行。

Callable任务本身是异步执行的,这意味着任务的执行不会阻塞主线程。然而,当你调用Future.get()方法时,它会阻塞当前线程(这里是主线程),直到对应的Callable任务完成并且结果变得可用。因此,尽管任务是并发执行的,但获取结果的方式是同步的。

如果你希望等待所有任务完成,你可以使用ExecutorService.awaitTermination(long timeout, TimeUnit unit)方法。这个方法会阻塞,直到所有的任务都完成或者超时为止。例如上面注释掉的代码;主线程会等待最多2000毫秒,看所有提交给executor的任务是否能在这段时间内完成。如果任务没有在指定时间内完成,awaitTermination方法会返回false。如果线程在等待过程中被中断,InterruptedException会被抛出。

 

四、使用spring注入的方式实现:Executor

    @Qualifier("asyncTaskExecutor")
    private final Executor asyncTaskExecutor;

    public void test(){
        CompletableFuture<Object> featuredCF = CompletableFuture
                .supplyAsync(() -> "Task 3", asyncTaskExecutor);
        Object o = featuredCF.get();
        System.out.println(o);
    }

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值