精华内容
下载资源
问答
  • 本文给大家分享java线程实现异步调用的方法,感兴趣的朋友跟着脚本之家小编一起学习吧
  • Java线程实现异步调用实例。运行Main可以看到结果。main是主线程,另有A,B,C三个线程用不同的时间跑完。
  • Java接口异步调用

    2020-08-26 00:11:43
    主要介绍了Java接口异步调用,下面我们来一起学习一下吧
  • java线程异步调用

    千次阅读 2018-11-07 09:54:13
    本文主要讲解生产环境中遇到的异步加载数据问题以及相应的解决思路。 系统登录的时候,需要根据用户ID生成一些和当前...在Java程序中,如果想实现异步调用方法的功能,需要通过线程方式实现,即实现java.lang.Ru...

    本文主要讲解生产环境中遇到的异步加载数据问题以及相应的解决思路。

    系统登录的时候,需要根据用户ID生成一些和当前用户有关的数据放在缓存里,如果不考虑异步调用,则整个登录过程可能需要近8S的时间,这肯定是无法接受的。因而需要在登录的时候,将这些与登录无关的数据操作提取出来,并放在异步进程中实现。

    在Java程序中,如果想实现异步调用方法的功能,需要通过线程方式实现,即实现java.lang.Runnable接口或者继承java.lang.Thread类,这里选择使用实现Runnable接口。考虑到是生产环境,还需要使用到ThreadPoolExecutor线程池。下面直接看代码示例:
    一、定义线程池实例服务

    public class ThreadPoolManager {
    public static ThreadPoolExecutor getInstance() {
            if (executor == null) {
                synchronized (ThreadPoolManager.class) {
                    if (executor == null) {
                        executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME,
                                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
                    }
                }
            }
            return executor;
        }
    }
    

    二、任务处理实现

    public class MyTask implements Runnable {
        @Override
        public void run() {
            // 具体业务处理
       		......
        }
    }
    

    三、放入线程池中执行

      public void testExecutorPool() {
            ThreadPoolExecutor executor = ThreadPoolManager.getInstance();
            executor.execute(new Mytask());
        }
    

    PS: ThreadPoolExecutor+Runnable实现方式是无返回结果的,如果需要拿到返回结果要使用ThreadPoolExecutor+Callable方式。


    ------------本文结束感谢您的阅读------------
    展开全文
  • 主要为大家详细介绍了Java线程异步Future机制的原理和实现,感兴趣的小伙伴们可以参考一下
  • 一、线程计数器回顾在《Java线程编程-(6)-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier》 这一篇中,我们使用线程计数器的方式实现了在主线程中等待计数的线程执行完之后在执行阻塞等待之后的...

    一、线程计数器回顾

    在《Java多线程编程-(6)-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier》 这一篇中,我们使用线程计数器的方式实现了在主线程中等待计数的线程执行完之后在执行阻塞等待之后的代码。看段代码回顾一下:

    public class SummonDragonDemo {
    
        private static final int THREAD_COUNT_NUM = 7;
        private static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT_NUM);
    
        public static void main(String[] args) throws InterruptedException {
    
            for (int i = 1; i <= THREAD_COUNT_NUM; i++) {
                int index = i;
                new Thread(() -> {
                    try {
                        System.out.println("第" + index + "颗龙珠已收集到!");
                        //模拟收集第i个龙珠,随机模拟不同的寻找时间
                        Thread.sleep(new Random().nextInt(3000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //每收集到一颗龙珠,需要等待的颗数减1
                    countDownLatch.countDown();
                }).start();
            }
            //等待检查,即上述7个线程执行完毕之后,执行await后边的代码
            countDownLatch.await();
            System.out.println("集齐七颗龙珠!召唤神龙!");
        }
    }

    这里简单的回顾了一下CountDownLatch,这是因为CountDownLatch也实现了类似异步调用的过程,只不过具体的任务由线程去执行,但是会阻塞在主线程的countDownLatch.await(); 处,(这里要将的Future同样也会阻塞,只是阻塞在了真正数据获取的位置!后边会讲到!)。

    二、什么是异步调用

    当我们调用一个函数的时候,如果这个函数的执行过程是很耗时的,我们就必须要等待,但是我们有时候并不急着要这个函数返回的结果。因此,我们可以让被调者立即返回,让他在后台慢慢的处理这个请求。对于调用者来说,则可以先处理一些其他事情,在真正需要数据的时候再去尝试获得需要的数据(这个真正需要数据的位置也就是上文提到的阻塞点)。这也是Future模式的核心思想:异步调用

    到了这里,你可能会想CountDownLatch不是也可以实现类似的功能的吗?也是可以让耗时的任务通过子线程的方式去执行,然后设置一个阻塞点等待返回的结果,情况貌似是这样的!但有时发现CountDownLatch只知道子线程的完成情况是不够的,如果在子线程完成后获取其计算的结果,那CountDownLatch就有些捉襟见衬了,所以JDK提供的Future类,不仅可以在子线程完成后收集其结果,还可以设定子线程的超时时间,避免主任务一直等待。

    看到这里,似乎恍然大悟了!CountDownLatch无法很好的洞察子线程执行的结果,使用Future就可以完成这一操作,那么Future何方神圣!下边我们就细细聊一下。

    三、Future模式

    虽然,Future模式不会立即返回你需要的数据,但是,他会返回一个契约 ,以后在使用到数据的时候就可以通过这个契约获取到需要的数据。

    这里写图片描述

    上图显示的是一个串行程序调用的流程,可以看出当有一个程序执行的时候比较耗时的时候,其他程序必须等待该耗时操作的结束,这样的话客户端就必须一直等待,知道返回数据才执行其他的任务处理。

    这里写图片描述

    上图展示的是Future模式流程图,在广义的Future模式中,虽然获取数据是一个耗时的操作,但是服务程序不等数据完成就立即返回客户端一个伪造的数据(就是上述说的“契约”),实现了Future模式的客户端并不急于对其进行处理,而是先去处理其他业务,充分利用了等待的时间,这也是Future模式的核心所在,在完成了其他数据无关的任务之后,最后在使用返回比较慢的Future数据。这样在整个调用的过程中就不会出现长时间的等待,充分利用时间,从而提高系统效率。

    1、Future主要角色

    这里写图片描述

    2、Future的核心结构图如下:

    这里写图片描述

    上述的流程就是说:Data为核心接口,这是客户端希望获取的数据,在Future模式中,这个Data接口有两个重要的实现,分别是:RealData和FutureData。RealData就是真实的数据,FutureData他是用来提取RealData真是数据的接口实现,用于立即返回得到的,他实际上是真实数据RealData的代理,封装了获取RealData的等待过程。

    说了这些理论的东西,倒不如直接看代码来的直接些,请看代码!

    四、Future模式的简单实现

    主要包含以下5个类,对应着Future模式的主要角色:

    这里写图片描述

    1、Data接口

    /**
     * 返回数据的接口
     */
    public interface Data {
    
        String getResult();
    }

    2、FutureData代码

    /**
     * Future数据,构造很快,但是是一个虚拟的数据,需要装配RealData
     */
    public class FutureData implements Data {
    
        private RealData realData = null;
        private boolean isReady = false;
    
        private ReentrantLock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
    
        @Override
        public String getResult() {
            while (!isReady) {
                try {
                    lock.lock();
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
            return realData.getResult();
        }
    
        public void setRealData(RealData realData) {
            lock.lock();
            if (isReady) {
                return;
            }
            this.realData = realData;
            isReady = true;
            condition.signal();
            lock.unlock();
        }
    }

    3、RealData代码

    public class RealData implements Data {
    
        private String result;
    
        public RealData(String param) {
            StringBuffer sb = new StringBuffer();
            sb.append(param);
            try {
                //模拟构造真实数据的耗时操作
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            result = sb.toString();
        }
    
        @Override
        public String getResult() {
            return result;
        }
    }

    4、Client代码

    public class Client {
    
        public Data request(String param) {
            //立即返回FutureData
            FutureData futureData = new FutureData();
            //开启ClientThread线程装配RealData
            new Thread(() -> {
                {
                    //装配RealData
                    RealData realData = new RealData(param);
                    futureData.setRealData(realData);
                }
            }).start();
            return futureData;
        }
    }

    5、Main

    /**
     * 系统启动,调用Client发出请求
     */
    public class Main {
    
        public static void main(String[] args) {
            Client client = new Client();
            Data data = client.request("Hello Future!");
            System.out.println("请求完毕!");
    
            try {
                //模拟处理其他业务
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("真实数据:" + data.getResult());
        }
    }
    

    6、执行结果:

    这里写图片描述

    五、JDK中的Future模式实现

    上述实现了一个简单的Future模式的实现,因为这是一个很常用的模式,在JDK中也给我们提供了对应的方法和接口,先看一下实例:

    public class RealData implements Callable<String> {
    
        private String result;
    
        public RealData(String result) {
            this.result = result;
        }
    
        @Override
        public String call() throws Exception {
            StringBuffer sb = new StringBuffer();
            sb.append(result);
            //模拟耗时的构造数据过程
            Thread.sleep(5000);
            return sb.toString();
        }
    }
    

    这里的RealData 实现了Callable接口,重写了call方法,在call方法里边实现了构造真实数据耗时的操作。

    public class FutureMain {
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
    
            FutureTask<String> futureTask = new FutureTask<>(new RealData("Hello"));
    
            ExecutorService executorService = Executors.newFixedThreadPool(1);
            executorService.execute(futureTask);
    
            System.out.println("请求完毕!");
    
            try {
                Thread.sleep(2000);
                System.out.println("这里经过了一个2秒的操作!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("真实数据:" + futureTask.get());
            executorService.shutdown();
        }
    }

    执行结果:

    这里写图片描述

    上述代码,通过:FutureTask<String> futureTask = new FutureTask<>(new RealData("Hello")); 这一行构造了一个futureTask 对象,表示这个任务是有返回值的,返回类型为String,下边看一下FutureTask的类图关系:

    这里写图片描述

    FutureTask实现了RunnableFuture接口,RunnableFuture接口继承了FutureRunnable接口。因为RunnableFuture实现了Runnable接口,因此FutureTask可以提交给Executor进行执行,FutureTask有两个构造方法,如下:

    构造方法1,参数为Callable:

    这里写图片描述

    构造方法2,参数为Runnable:

    这里写图片描述

    上述的第二个构造方法,传入的是Runnable接口的话,会通过Executors.callable()方法转化为Callable,适配过程如下:

    这里写图片描述

    这里写图片描述

    这里为什么要将Runnable转化为Callable哪?首先看一下两者之间的区别:

    (1) Callable规定的方法是call(),Runnable规定的方法是run();
    (2) Callable的任务执行后可返回值,而Runnable的任务是不能返回值得; 
    (3) call()方法可以抛出异常,run()方法不可以;
    (4) 运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。

    最关键的是第二点,就是Callable具有返回值,而Runnable没有返回值。Callable提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。

    计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()throws InterruptedException或者ExecutionException;如果线程已经取消,会抛出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。

    一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?> 形式类型、并返回 null 作为底层任务的结果。


    参考文章:

    1、http://blog.csdn.net/ghsau/article/details/7451464

    2、http://blog.csdn.net/heyutao007/article/details/19072675

    展开全文
  • 因此可以使用异步调用的方法,不阻塞当前其他任务的执行。 小栗子 首先我们先要创建一个线程池,可以根据自己的需求创建,什么IO密集型参数设置,CPU密集型参数的设置。这里我们仅仅想让10个任务一起跑。 ...

    前言

    在我们的业务中很可能会碰到需要执行一段时间的任务,并且如果同步的话就会造成一些无谓的等待。因此可以使用异步调用的方法,不阻塞当前其他任务的执行。

    小栗子

    首先我们先要创建一个线程池,可以根据自己的需求创建,什么IO密集型参数设置,CPU密集型参数的设置。这里我们仅仅想让10个任务一起跑。

    ExecutorService threadPool = new ThreadPoolExecutor(
                            10,
                            10,
                            0,
                            TimeUnit.SECONDS,
                            new SynchronousQueue<>(),
                            new ThreadPoolExecutor.AbortPolicy());
    

    然后模拟下需要异步调用的业务的执行,这里我的n给不同线程设置了不同的执行时间,在判断超时时,会有部分线程无法完成任务。
    AtomicInteger atomicInteger = new AtomicInteger(5);
    List<Future<Integer>> futures = new ArrayList<>(); //存储结果
    for (int i = 0; i < 10; i++) {
                Future<Integer> submit = completionService.submit(() -> {
                    int n = atomicInteger.getAndIncrement();
                    int h = 0;
                    for (int j = n * 10; j < n * 10 + n; j++) {
                        h += j;
                        TimeUnit.SECONDS.sleep(1); //暂停线程1s
                    }
                    return h;
    
                });
                futures.add(submit);
            }
    

    现在执行下其他的业务操作。

    然后设置一些调用其他接口超时的时间,避免过长等待并开始获取下调用的结果。

    		Set<AjaxResult> flags = new HashSet<>();
            List<AjaxResult> FAILS =new LinkedList<>();
            long startTime = System.currentTimeMillis();
            long timeout = 1000 * 10;
             while (flags.size()+FAILS.size()<futures.size()) {
                for (Future<Integer> o : futures) {
                    if (System.currentTimeMillis() - startTime > timeout ){// 如果超时采取一定措施,或者返回一个失败。
                        FAILS.add(new AjaxResult("fail",0));
                        if(flags.size()+FAILS.size()>=futures.size()){
                            break;
                        }
                        continue;
                    }
                    if (o.isDone()) {
                        flags.add(new AjaxResult("success", o.get()));
                    }
                }
    
             }
            long endTime = System.currentTimeMillis();
    

    这里将结果分失败和成功进行存储。并记录处理的时间


    接下来看下最后输出结果

    		System.out.println("执行结束");
            System.out.println("耗时" + (endTime - startTime));
            System.out.println("结果" + flags.toString());
            System.out.println("失败" + FAILS.toString());
            System.exit(0);
    

    在这里插入图片描述
    本方法纯属瞎玩,仅供参考。

    下面是全部的代码

    public class InitConfig {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            ExecutorService threadPool = new ThreadPoolExecutor(
                            10,
                            10,
                            0,
                            TimeUnit.SECONDS,
                            new SynchronousQueue<>(),
                            new ThreadPoolExecutor.AbortPolicy());
            CompletionService<Integer> completionService = new ExecutorCompletionService<>(threadPool);
            AtomicInteger atomicInteger = new AtomicInteger(5);
            List<Future<Integer>> futures = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                Future<Integer> submit = completionService.submit(() -> {
                    int n = atomicInteger.getAndIncrement();
                    int h = 0;
                    for (int j = n * 10; j < n * 10 + n; j++) {
                        h += j;
                        TimeUnit.SECONDS.sleep(1); //暂停线程1s
                    }
                    return h;
    
                });
                futures.add(submit);
            }
            Set<AjaxResult> flags = new HashSet<>();
            List<AjaxResult> FAILS =new LinkedList<>();
            long startTime = System.currentTimeMillis();
            long timeout = 1000 * 10;
             while (flags.size()+FAILS.size()<futures.size()) {
                for (Future<Integer> o : futures) {
                    if (System.currentTimeMillis() - startTime > timeout ){
                        FAILS.add(new AjaxResult("fail",0));
                        if(flags.size()+FAILS.size()>=futures.size()){
                            break;
                        }
                        continue;
                    }
                    if (o.isDone()) {
                        flags.add(new AjaxResult("success", o.get()));
                    }
                }
    
             }
            long endTime = System.currentTimeMillis();
            System.out.println("执行结束");
            System.out.println("耗时" + (endTime - startTime));
            System.out.println("结果" + flags.toString());
            System.out.println("失败" + FAILS.toString());
            System.exit(0);
        }
    
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        @ToString
        @EqualsAndHashCode
        static class AjaxResult {
            private String ret;
            private Integer data;
        }
    
    
    }
    
    展开全文
  • 主要介绍了java实现HttpClient异步请求资源的方法,实例分析了java基于http协议实现异步请求的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • CompletableFuture 详解 CompletableFuture类实现了CompletionStage和Future接口...Future是Java 5添加的类,用来描述一个异步计算的结果,但是获取一个结果时方法较少,要么通过轮询isDone,确认完成后,调用get()...

    转载博文:https://blog.csdn.net/mrxiky/article/details/78962614

    CompletableFuture 详解

    CompletableFuture类实现了CompletionStage和Future接口。Future是Java 5添加的类,用来描述一个异步计算的结果,但是获取一个结果时方法较少,要么通过轮询isDone,确认完成后,调用get()获取值,要么调用get()设置一个超时时间。但是这个get()方法会阻塞住调用线程,这种阻塞的方式显然和我们的异步编程的初衷相违背。
    为了解决这个问题,JDK吸收了guava的设计思想,加入了Future的诸多扩展功能形成了CompletableFuture。

    CompletionStage是一个接口,从命名上看得知是一个完成的阶段,它里面的方法也标明是在某个运行阶段得到了结果之后要做的事情。

    ………………

     

    展开全文
  • Java 实现异步调用

    万次阅读 热门讨论 2018-04-03 15:27:12
    首先 我遇到的问题是 接口调用时需要更新缓存 而更新缓存又是个说快不快的过程 所以打算做异步调用 返回我所需要的结果即可 ,至于缓存什么时候更新完 就不是我所需要关注的了废话不多说 上代码public class ...
  • Java实现异步调用方法(jdk1.8)

    千次阅读 2020-10-26 16:38:23
    点击上方“秋秋秋影影影”,并“星标置顶” 喜欢我的都关注我了 阅读本文大约需要 30秒 jdk1.8开始的Future 很多时候,我们需要调用一个耗时方法,但是我们并不需要等待它执行完,才继续后面的...
  • 教你如何用 Java 实现异步调用

    千次阅读 2019-09-12 12:16:39
    导读 本教程教你如何使用Java实现异步调用。 一、创建线程 @Test public void test0() throws Exception { System.out.println("main函数开始执行"); Thr...
  • 项目中用到了多线程,但是线程异步操作时无法调用Service层和Dao层的函数,进行数据库的读取,然后就想办法如何往线程中注入Service和Dao层的bean。
  • Java线程实现异步调用

    千次阅读 2017-03-21 16:18:59
    原文地址:Java线程实现异步调用作者:chuansir 在JAVA平台,实现异步调用的角色有如下三个角色:调用者 提货单 真实数据 一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单.然后在过一断时间后凭...
  • SpringBoot使用多线程实现异步调用

    千次阅读 2018-03-22 21:40:06
    一、在想要异步执行的方法上加上@Async注解二、在主函数运行类上开启异步注解@EnableAsync
  • JAVA异步调用

    万次阅读 2017-12-11 10:14:53
    那么后台的异步调用改怎么实现呢?1、 使用callable接口,加线程池 2、 使用JAVA的回调机制 3、 使用spring框架默认的异步调用方式一、第一种方式是比较简单,也比较常用的方式,下面看一段示例代码:public void ...
  • Java如何实现方法级的异步调用 业务需求: 方法A里面调用方法B,但是方法B执行的时间太久,如果方法A要等方法B 执行完再返回页面,页面需要等很久,而且方法B的执行结果不影响方法A的后续执行。 因此,这里方法B异步...
  • 要在springboot中使用异步调用方法,只要在被调用的方法上面加上@Async就可以了 1.准备工作 准备一个springboot工程,在Application类上加上EnableAsync注解开启异步 /** * @Author: zgd * @Date...
  • java线程异步

    千次阅读 2019-05-17 17:49:29
    背景 最近遇到多数据库执行sql处理后生成报表,项目原有逻辑是单线程同步执行的,随着数据量的增大时间越来越...实现 代码 伪代码 //创建线程池 ExecutorService executor = Executors.newFixedThreadPool(4);...
  • java实现异步调用的方法

    万次阅读 2018-03-08 00:19:29
    概念的理解同步/异步:关于同步,我们知道jvm解释执行class文件时候,就是按照代码从上到下的顺序执行的,这里我们正常的程序开发流程,如果一个方法中执行了doSomething1,doSomething2两个方法,正常情况下...
  • 下面小编就为大家带来一篇浅谈java异步线程超时导致的服务异常。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Java线程异步执行多个方法

    千次阅读 2019-06-25 12:08:46
    https://jingyan.baidu.com/article/20095761feaa9fcb0721b4d2.html
  • @Async()注解快速实现 通过使用@Async注解就能简单的将原来的同步函数变为异步函数; 在你需要异步的方法上使用@Async注解;@Async()注解可以写上线程池名称,这样就会指定使用的线程池,当然我们需要自定义线程池...
  • 1 什么是通过线程池实现代码的异步执行 1.1 什么是同步执行 与异步相对的是同步,这里先解释一下同步执行,同步执行就是平时执行我们的代码,由上至下顺序执行,中间如果有异常或错误出现不会继续往下执行。这也...
  • java实现异步调用实例

    千次阅读 2018-03-27 15:13:46
    JAVA平台,实现异步调用的角色有如下三个角色: 调用者 取货凭证 真实数据 一个调用者在调用耗时操作,不能立即返回数据时,先返回一个取货凭证.然后在过一断时间后凭取货凭证来获取真正的数据. 所以连结调用者和...
  • 主要介绍了Java利用ExecutorService实现同步执行大量线程,ExecutorService可以维护我们的大量线程在操作临界资源时的稳定性。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 186,377
精华内容 74,550
关键字:

java实现线程异步调用

java 订阅