首页 > 编程语言 >java线程异步方法

java线程异步方法

时间:2024-10-21 13:34:52浏览次数:8  
标签:异步 java System 线程 executor println public

异步的八种实现方式:

线程异步 Thread/Runnable
Future + Callable
异步框架 CompletableFuture
Spring 注解 @Async
Spring ApplicationEvent 事件
第三方异步框架,比如 Hutool 的 ThreadUtil
Guava 异步
消息队列
1、线程异步

public class ThreadTest implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        new Thread(threadTest).start();
    }

}

当然,如果每次都创建一个 Thread 线程,频繁的创建、销毁,浪费系统资源,我们可以采用线程池:【Thread】线程池的 7 种创建方式及自定义线程池

2、Future 异步

public class FutureTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        Future<String> future = executor.submit(() -> {
            Thread.sleep(2000);
            return "this is future execute final result!!!";
        });
        //这里需要返回值时会阻塞主线程
        String result = future.get();
        System.out.println(result);
        executor.shutdown();
    }

}

Future的不足之处的包括以下几点:

无法被动接收异步任务的计算结果:虽然我们可以主动将异步任务提交给线程池中的线程来执行,但是待异步任务执行结束之后,主线程无法得到任务完成与否的通知,它需要通过get方法主动获取任务执行的结果。
Future件彼此孤立:有时某一个耗时很长的异步任务执行结束之后,你想利用它返回的结果再做进一步的运算,该运算也会是一个异步任务,两者之间的关系需要程序开发人员手动进行绑定赋予,Future并不能将其形成一个任务流(pipeline),每一个Future都是彼此之间都是孤立的,所以才有了后面的CompletableFuture,CompletableFuture就可以将多个Future串联起来形成任务流。
Futrue没有很好的错误处理机制:截止目前,如果某个异步任务在执行发的过程中发生了异常,调用者无法被动感知,必须通过捕获get方法的异常才知晓异步任务执行是否出现了错误,从而在做进一步的判断处理
3、CompletableFuture
关于 CompletableFuture 更多详情请看:【异步】Futurn、FutureTask、CompletionService、CompletableFuture

public static void thenRunAsync() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread() + " cf1 do something....");
        return 1;
    });
    CompletableFuture<Void> cf2 = cf1.thenRunAsync(() -> {
        System.out.println(Thread.currentThread() + " cf2 do something...");
    });
    //等待任务1执行完成
    System.out.println("cf1结果->" + cf1.get());
    //等待任务2执行完成
    System.out.println("cf2结果->" + cf2.get());
}

4、Spring 注解 @Async

@Configuration
public class ThreadPoolConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        //返回可用处理器的Java虚拟机的数量 12
        int i = Runtime.getRuntime().availableProcessors();
        System.out.println("系统最大线程数  : " + i);
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程池大小
        executor.setCorePoolSize(16);
        //最大线程数
        executor.setMaxPoolSize(20);
        //配置队列容量,默认值为Integer.MAX_VALUE
        executor.setQueueCapacity(99999);
        //活跃时间
        executor.setKeepAliveSeconds(60);
        //线程名字前缀
        executor.setThreadNamePrefix("asyncServiceExecutor -");
        //设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行
        executor.setAwaitTerminationSeconds(60);
        //等待所有的任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }

}

@Service
@EnableAsync
public class AsyncServiceImpl implements AsyncService {

    @Override
    @Async("taskExecutor")
    public String sendSms() {
        System.out.println(Thread.currentThread().getName());
        return null;
    }

    @Override
    @Async("taskExecutor")
    public String sendEmail() {
        System.out.println(Thread.currentThread().getName());
        return null;
    }

}

在实际项目中, 使用 @Async 调用线程池,推荐等方式是是使用自定义线程池的模式,不推荐直接使用 @Async 直接实现异步

5、Spring ApplicationEvent 事件

Spring 中使用事件只需要以下的几个步骤:

定义事件,继承 ApplicationEvent
定义监听,要么实现 ApplicationListener 接口,要么在方法上添加 @EventListener 注解
定义发布事件接口,调用 ApplicationContext.publishEvent() 或者 ApplicationEventPublisher.publishEvent();
业务调用发布事件
@Getter
@Setter
public class BaseEvent<T> extends ApplicationEvent {

    private T data;

    public BaseEvent(Object source) {
        super(source);
    }

    public BaseEvent(Object source, T data) {
        super(source);
        this.data = data;
    }

}

@Component
public class BaseEventListener implements ApplicationListener<BaseEvent<UserVo>> {

    @Override
    @Async("taskExecutor")
    public void onApplicationEvent(BaseEvent<UserVo> baseEvent) {
        UserVo eventData = baseEvent.getData();
        // TODO 业务处理
    }

}

@Autowired
private ApplicationContext applicationContext;

@GetMapping("/pubEvent")
public void pubEvent() {
    BaseEvent<UserVo> baseEvent = new BaseEvent<>("event", new UserVo());
    applicationContext.publishEvent(baseEvent);
}

6、Hutool 的 ThreadUtil

public static void main(String[] args) {
    for (int i = 0; i < 3; i++) {
        ThreadUtil.execAsync(() -> {
            ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
            int number = threadLocalRandom.nextInt(20) + 1;
            System.out.println(number);
        });
        log.info("当前第:" + i + "个线程");
    }

    log.info("task finish!");
}

7、 Guava 异步

public static void test() {
    ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
    final ListenableFuture<Integer> listenableFuture = executorService.submit(() -> {
        log.info("callable execute...");
        TimeUnit.SECONDS.sleep(1);
        return 1;
    });

    Futures.addCallback(listenableFuture, new FutureCallback<Integer>() {
        @Override
        public void onSuccess(@Nullable Integer integer) {
            System.out.println("Get listenable future's result with callback " + integer);
        }
        @Override
        public void onFailure(Throwable throwable) {
            throwable.printStackTrace();
        }
    }, Executors.newCachedThreadPool());
}

8、 消息队列

常用的消息队列:RabbitMq、RocketMq

  

标签:异步,java,System,线程,executor,println,public
From: https://www.cnblogs.com/stevenduxiang/p/18489303

相关文章

  • Java多线程技能
      2.创建多线程的方式,有几种?怎么创建继承Thread类(一般不单独用)实现Runnable接口+Thread对象实现Callable接口+FutureTask<>对象+Thread对象线程池+(实现Callable接口+FutureTask<>对象)或者(实现Runnable接口)3.Thread类的常见APIcurrentThread()获取当前......
  • Java 中的数据加密和安全传输_1
    在Java中实现数据加密和安全传输涉及几个关键技术:使用加密算法、实施安全的密钥管理、采用安全传输协议。加密算法如AES和RSA用于保护数据的机密性,防止未授权访问。安全的密钥管理确保只有授权用户才能解密数据。而安全传输协议如SSL/TLS保护数据在网络中的传输。其中,安全传输协......
  • 从零开始写多线程
    1.Java多线程的基本概念1.1线程与进程进程:是操作系统分配资源的基本单位,每个进程都有独立的内存空间。线程:是进程内的一个执行单元,同一进程中的线程共享进程的内存空间,线程间的通信更为高效。1.2线程的好处提高系统响应性:可以实现用户界面与后台处理的并发执行,使得程序......
  • Java基础·环境搭建与语法
    Java初识Java简介Java是一门面向对象的程序设计语言1995年由sun公司发布2010年sun公司被Oracle公司收购JDK版本是8.0JVMJVM(JavaVirtualMachine),Java虚拟机JVM是Java平台无关性实现的关键Java程序执行流程JDKJDK(JavaDevelopmentKit),Java语言的软件开发工具包两......
  • Java常量与变量
    标识符号的命名规则标识符可以由字母、数字、下划线()和美元符($)组成,不能以数字开头标识符严格区分大小写标识符不能是Java关键字和保留字标识符的命名最好能反映出其作用关键字变量什么是变量变量的三个元素:变量类型、变量名和变量值变量名的命名规则满足标识符命名......
  • java+vue计算机毕设废品上门回收预约系统【开题+程序+论文+源码】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着社会经济的快速发展和人民生活水平的不断提高,各类废品的产生量也在急剧增加。传统的废品回收方式往往依赖于街头巷尾的废品收购站或回收人员,这种......
  • java+vue计算机毕设非遗优品交易系统的设计与实现【开题+程序+论文+源码】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在全球化与现代化的浪潮中,非物质文化遗产(简称“非遗”)作为民族文化的瑰宝,承载着丰富的历史记忆与独特的文化价值。然而,随着时代的变迁,许多非遗项目面......
  • java+vue计算机毕设电影推荐系统【开题+程序+论文+源码】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和互联网娱乐产业的蓬勃兴起,电影作为一种重要的文化娱乐形式,已经深入人们的日常生活。近年来,电影市场的规模不断扩大,电影数量......
  • java+vue计算机毕设儿童培训管理系统的设计与实现【开题+程序+论文+源码】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着社会的快速发展和教育理念的不断进步,儿童培训行业迎来了前所未有的发展机遇。越来越多的家长开始重视孩子的全面发展,不仅关注学校的传统教育,还积......
  • 登录功能-Java实现token的生成与验证
    一、token与cookie相比较的优势1、支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的;2、无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的sessionID在服务端查找对应的session;3、无需绑定到一个特殊的身份......