并发编程之五FutureTask

这篇具有很好参考价值的文章主要介绍了并发编程之五FutureTask。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

futureTask实现了Runnable, Future接口,Future接口有如下定义:

    /**
     * 取消任务,如果任务已经在执行,mayInterruptIfRunning为true,则
     * 向执行线程发送interrupt事件,否则任由任务执行完毕。
     * 返回值为是否取消成功
     */
    boolean cancel(boolean mayInterruptIfRunning);

    // 任务是否已经被取消
    boolean isCancelled();

    // 任务是否已经执行完毕
    boolean isDone();

    /** 
     * 等待并获取结果,会抛出以下异常
     * 1. CancellationException 任务被取消
     * 2. ExecutionException 任务执行异常
     * 3. InterruptedException 执行线程在等待时收到interrupted事件
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    /** 
     * 等待并获取结果,timeout是最大等待时间,会抛出以下异常
     * 1. CancellationException 任务被取消
     * 2. ExecutionException 任务执行异常
     * 3. InterruptedException 执行线程在等待时收到interrupted事件
     * 4. 等待超时
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

1. isDone示例

package org.example.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask running");
            return "ok";
        });

        // 提交线程池之前,futureTask的状态为未执行
        assertThat(futureTask).isNotDone();
        executorService.execute(futureTask);

        // 等待100ms后,执行成功
        assertThat(futureTask).succeedsWithin(100L, TimeUnit.MILLISECONDS, InstanceOfAssertFactories.STRING)
                .contains("ok");
    }
}

2. cancel和 isCancelled

2.1 任务执行前cancel

示例:

package org.example.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask running");
            return "ok";
        });

        // 任务执行前cancel
        futureTask.cancel(false);
        assertThat(futureTask).isCancelled().isNotDone();
        executorService.execute(futureTask);

        // 取消的任务get会报取消异常
        assertThatExceptionOfType(CancellationException.class).isThrownBy(futureTask::get);
        
        // get后futureTask变为isDone;
        assertThat(futureTask).isCancelled().isDone();
    }
}

2.2 任务执行中取消任务

    示例1:取消,不通知任务线程中断

package org.example.concurrent;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @SneakyThrows
    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask start");
            sleep(300L);
            log.debug("futureTask end");
            return "ok";
        });
        executorService.execute(futureTask);

        // 等待100毫秒,此时futureTask正在运行, 然后取消任务
        sleep(100L);
        futureTask.cancel(false);

        // 取消的任务get会报取消异常
        assertThatExceptionOfType(CancellationException.class).isThrownBy(futureTask::get);

        // get后futureTask变为isDone;
        assertThat(futureTask).isCancelled().isDone();

        // 继续等待1秒,会发现任务会执行完毕
        sleep(1000L);
    }

    @SneakyThrows
    private void sleep(long delay) {
        TimeUnit.MILLISECONDS.sleep(delay);
    }
}

执行日志:

11:53:58.340 [pool-1-thread-1] DEBUG o.example.concurrent.FutureTaskTest - futureTask start
11:53:58.649 [pool-1-thread-1] DEBUG o.example.concurrent.FutureTaskTest - futureTask end

示例2:取消并通知任务线程中断(如果线程处于阻塞中,会感知到自身中断)

package org.example.concurrent;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @SneakyThrows
    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask start");
            try {
                sleep(300L);
            } catch (Exception e) {
                // 捕获打印异常名称并重新抛出
                log.error("catch Exception:{}", e.getClass().getSimpleName());
                throw e;
            }
            log.debug("futureTask end");
            return "ok";
        });
        executorService.execute(futureTask);

        // 等待100毫秒,此时futureTask正在运行, 然后取消任务
        sleep(100L);
        futureTask.cancel(true);

        // 取消的任务get会报取消异常
        assertThatExceptionOfType(CancellationException.class).isThrownBy(futureTask::get);

        // get后futureTask变为isDone;
        assertThat(futureTask).isCancelled().isDone();

        // 继续等待1秒,会发现任务会执行完毕
        sleep(1000L);
    }

    @SneakyThrows
    private void sleep(long delay) {
        TimeUnit.MILLISECONDS.sleep(delay);
    }
}

执行过程中,futureTask执行线程处于休眠中,能够感知到线程中断,执行结果如下:

11:59:10.410 [pool-1-thread-1] DEBUG o.example.concurrent.FutureTaskTest - futureTask start
11:59:10.513 [pool-1-thread-1] ERROR o.example.concurrent.FutureTaskTest - catch Exception:InterruptedException
11:59:10.515 [pool-1-thread-1] DEBUG o.example.concurrent.FutureTaskTest - futureTask end

示例3:重复取消任务,会取消失败

package org.example.concurrent;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @SneakyThrows
    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask start");
            sleep(300L);
            log.debug("futureTask end");
            return "ok";
        });
        executorService.execute(futureTask);

        // 等待100毫秒,
        sleep(100L);

        // 此时futureTask正在运行, 然后取消任务, 如果重复取消,会返回失败
        assertThat(futureTask.cancel(false)).isTrue();
        assertThat(futureTask.cancel(false)).isFalse();

        // 取消的任务get会报取消异常
        assertThatExceptionOfType(CancellationException.class).isThrownBy(futureTask::get);
    }

    @SneakyThrows
    private void sleep(long delay) {
        TimeUnit.MILLISECONDS.sleep(delay);
    }
}

2.3 任务执行完成后cancel

        任务执行完毕后在取消任务执行,取消动作会失败。参考下面的代码:

package org.example.concurrent;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @SneakyThrows
    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask start");
            log.debug("futureTask end");
            return "ok";
        });
        executorService.execute(futureTask);

        // 等待100毫秒,此时futureTask已经执行完毕, 取消任务执行会失败
        sleep(100L);
        assertThat(futureTask.cancel(true)).isFalse();

        // 判断执行成功
        assertThat(futureTask).succeedsWithin(0L, TimeUnit.MILLISECONDS, InstanceOfAssertFactories.STRING)
                .contains("ok");
    }

    @SneakyThrows
    private void sleep(long delay) {
        TimeUnit.MILLISECONDS.sleep(delay);
    }
}

3. get等待指定时间

get指定最大等待时间,如果超出此时间,则会抛出TimeoutException异常:文章来源地址https://www.toymoban.com/news/detail-414144.html

package org.example.concurrent;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.*;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

@Slf4j
public class FutureTaskTest {

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @SneakyThrows
    @Test
    public void test() {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            log.debug("futureTask start");
            sleep(1000L);
            log.debug("futureTask end");
            return "ok";
        });
        executorService.execute(futureTask);

        // get等待10毫秒,由于futureTask会执行1秒钟,get会报超时异常
        assertThatExceptionOfType(TimeoutException.class).isThrownBy(() -> futureTask.get(10L, TimeUnit.MILLISECONDS));
    }

    @SneakyThrows
    private void sleep(long delay) {
        TimeUnit.MILLISECONDS.sleep(delay);
    }
}

到了这里,关于并发编程之五FutureTask的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java闭锁之使用FutureTask实现预加载

    FutureTask也可以用作闭锁;FutureTask的计算是通过Callable来实现的,相当于一种可生成结果的Runnable,并且可以处于3种状态,分别是 等待运行(waiting to run) 、 正在运行(Running) 、和 运行完成(Completed) ,而 运行完成 表示计算的所有可能结束方式,包括 正常结束 , 由于取消而结

    2024年02月08日
    浏览(25)
  • 妙用 FutureTask + 线程池:轻松解决接口超时问题!

    来源:blog.csdn.net/qq_44384533/article/details/112324224 之前红包权益领取查询的接口超时了,因为有用户订购的权益有点多 用线程池+ FutureTask将1个查询拆分成多个小查询 选择FutureTask是因为它具有仅执行1次run()方法的特性(即使有多次调用也只执行1次),避免了重复查询的可能。而且

    2024年02月05日
    浏览(31)
  • JUC-线程Callable使用与FutureTask源码阅读

    Callable简单使用 带返回值的线程(实现implements Callable返回值类型),使用示例 FutureTask面向对象方式学习 为了定义这样一个事物“有返回结果”,暂且称之为RunnableFuture。它集合了Runnable和Future两种事物 (其中Future接口 表示了一个任务的生命周期,是一个可取消的异步运算,可

    2024年02月04日
    浏览(26)
  • Java 高级应用-多线程-(四)FutureTask的介绍及使用

    Java多线程之FutureTask的介绍及使用 FutureTask属于java.util.concurrent 包;FutureTask表示可取消的异步计算。FutureTask类提供了一个Future的基本实现 ,具有启动和取消计算的方法,查询计算是否完整,并检索计算结果。结果只能在计算完成后才能检索; 如果计算尚未完成,则get方法将阻

    2024年02月07日
    浏览(27)
  • 如何解决java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@7566d7cf r...

    Java中的 java.util.concurrent.RejectedExecutionException 异常表示无法将任务提交到线程池中执行。这通常是因为线程池处于关闭状态或者已经达到了最大线程数,无法再接受新的任务。 要解决这个异常,你可以考虑以下几种方法: 检查线程池的状态,确保它处于可以接受新任务的状态

    2024年02月13日
    浏览(43)
  • Java并发编程详解:实现高效并发应用的关键技术

    在当前的计算机领域,高效的并发编程对于Java开发人员而言变得越发重要。作为流行的编程语言,Java提供了强大的并发编程支持,使开发人员能够充分发挥多核处理器和线程的潜力,构建高性能、高吞吐量的应用程序。本文将深入探讨Java并发编程的关键技术,包括线程安全

    2024年02月13日
    浏览(34)
  • 【并发编程】深入理解Java并发之synchronized实现原理

    分析: 通过 new MyThread() 创建了一个对象 myThread ,这时候堆中就存在了共享资源 myThread ,然后对 myThread 对象创建两个线程,那么thread1线程和thread2线程就会共享 myThread 。 thread1.start() 和 thead2.start() 开启了两个线程,CPU会随机调度这两个线程。假如 thread1 先获得 synchronized 锁,

    2024年02月04日
    浏览(50)
  • Java 高级应用-多线程-(一)实现 Runnable 接口与继承 Thread 类

    1.1 程序、进程与线程 • 程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段 静态的代码,静态对象。 • 进程(process):程序的一次执行过程,或是正在内存中运行的应用程序。如:运行 中的 QQ,运行中的网易音乐播放器。 – 每个进程都有一

    2024年02月08日
    浏览(44)
  • 「并发编程实战」接口幂等性设计的最佳实现(8种实现方案)

    文章参考: 实战!聊聊幂等设计 基于幂等表思想的幂等实践 追忆四年前:一段关于我被外企CTO用登录注册吊打的不堪往事 弹力设计篇之“幂等性设计” 幂等是一个数学与计算机科学概念。 在数学中,幂等用函数表达式就是: f(x) = f(f(x)) 。比如求绝对值的函数,就是幂等的

    2024年01月22日
    浏览(32)
  • 计算机网络编程 | 并发服务器代码实现(多进程/多线程)

    欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。 专栏:《网络编程》 当涉及到构建高性能的服务

    2024年02月08日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包