精华内容
下载资源
问答
  • 2020-08-20 20:07:26

    前言

    在使用多线程的场景中,经常需要获取多线程的执行结果,有的甚至还需要合并不同线程的执行结果进行后续的业务逻辑处理等,下面对常用的几种获取与合并多线程的执行结果的方式做一下小结

    1、thread.join的方式

    在jdk8之前,线程本身提供了join的方法,可以让其他线程加入到当前主线程中,等到所有的线程执行完毕自己的逻辑之后,主线程就可以获取并合并各个线程的结果了,下面看实例代码

    public class ThreadJoinTest1 {
    
        static int sum1 = 0;
        static int sum2 = 0;
    
        public static void main(String[] args) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + " start.");
            Thread t1 = new Thread(()->{
                System.out.println( " t1 start.");
                try {
                    for (int i = 0; i < 15; i++) {
                        Thread.sleep(200);
                        sum1 +=i;
                    }
                    System.out.println("t1 end.");
                } catch (Exception e) {
                    System.out.println("Ex
    更多相关内容
  • 如何获取多线程执行结果-java

    万次阅读 2021-08-12 16:08:05
    在日常的项目开发中,我们会经常遇到通过多线程执行程序并需要返回执行结果的场景,下面我们就对获取多线程返回结果的几种方式进行一下归纳,并进行简要的分析与总结。 一、Thread.join 在一些简单的应用场景中...

    在日常的项目开发中,我们会经常遇到通过多线程执行程序并需要返回执行结果的场景,下面我们就对获取多线程返回结果的几种方式进行一下归纳,并进行简要的分析与总结。

    一、Thread.join

    在一些简单的应用场景中我们可以使用线程本身提供的join方法,我们知道join方法的目的是让一个线程等待另一个线程结束后才能执行,利用此原理我们可以设置一个监控线程用来等待程序线程执行完毕后输出返回结果,下面我们看下具体示例代码

    首先定义一个结果实体类

    public class Result {
        private String value;
    
        public String getValue() {
            return value;
        }
    
        public void setValue(String value) {
            this.value = value;
        }
    }

    定义工作线程,模拟程序执行并输出线程执行结果

    public class WorkThread extends Thread {
        
        private Result result ;
        
        public void init(Result result) {
            this.result = result;
        }
        
        public void run() {
            try {
                Thread.sleep(1000*10);//模拟程序执行
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            result.setValue("线程执行完毕,输出结果");
        }
    
    }

    主线程等待工作线程执行,并获取工作线程的执行成果

    public class MainThread {
        public static void main(String[] args) throws InterruptedException {
            Result result = new Result();
            WorkThread workThread = new WorkThread();
            workThread.init(result);
            System.out.println("线程启动");
            workThread.start();
            System.out.println("线程等待");
            // 等待work线程运行完再继续运行
            workThread.join();
            System.out.println("线程执行结果:"+result.getValue());
        }
    }

    输出结果

    线程启动
    线程等待
    线程执行结果:线程执行完毕,输出结果

    以上代码通过Thread.join的方式,模拟了一个最基本的获取线程执行结果场景,采用Thread.join的方式虽然使用方便,但这种原生的方式只适用于一些简单的应用场景中,其主要存在以下问题:

    1、获取多个线程返回结果时较为繁琐,需要自己手动实现;

    2、与线程池无法配合使用;

    3、工作线程内部执行复杂度与耗时不确定,程序需要额外完善;

    4、本质上还是同步返回结果,主线程阻塞;

    二、CountDownLatch

    CountDownLatch做为jdk提供的多线程同步工具,CountDownLatch其实本质上可以看做一个线程计数器,统计多个线程执行完成的情况,适用于控制一个或多个线程等待,直到所有线程都执行完毕的场景,因此我们可以利用其功能特点实现获取多个线程的执行结果,一定程度上弥补了Thread.join的不足,代码示例如下:

    工作线程

    public class WorkThread extends Thread {
        private Vector<Result> vectors ;
        
         private CountDownLatch countDownLatch;
        
        public WorkThread(CountDownLatch countDownLatch) {
            this.countDownLatch=countDownLatch;
        }
        
        public void init(Vector<Result> vectors) {
            this.vectors = vectors;
        }
        
        public void run() {
            try {
                Thread.sleep(1000*3);//模拟程序执行
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Result result = new Result();
            result.setValue(Thread.currentThread().getName()+"线程执行完毕,输出结果");
            vectors.add(result);//结果放入Vector中
            countDownLatch.countDown();
        }
    }

    主线程

    public class MainThread {
    
        public static void main(String[] args) throws InterruptedException {
            Vector<Result> vectors = new Vector<Result>();//定义一个Vector做为存储返回结果的容器;
            final CountDownLatch countDownLatch = new CountDownLatch(5);
            // 启动多个工作线程
            for (int i = 0; i < 5; i++) {
                WorkThread workThread = new WorkThread(countDownLatch);
                workThread.init(vectors);
                workThread.start();
            }
            System.out.println("主线程等待工作线程执行");
            countDownLatch.await();
            for (int i=0; i<vectors.size(); i++) {
                System.out.println(vectors.get(i).getValue());        
            }
            
        }
    
    }

    输出结果

    主线程等待工作线程执行
    Thread-0线程执行完毕,输出结果
    Thread-1线程执行完毕,输出结果
    Thread-2线程执行完毕,输出结果
    Thread-4线程执行完毕,输出结果
    Thread-3线程执行完毕,输出结果

    通过利用jdk的多线程工具类CountDownLatch,我们可以等待多个线程执行完毕后获取结果,但这种方式局限性较多,如果你的应用场景中启动的线程次数是固定的且需要等待执行结果全部返回后统一处理,使用CountDownLatch是一个不错的选择。

    三、Future

    1、Future与FutureTask

    使用Future,包括 FutureTask、CompletionService、CompletableFuture等

    首先我们使用Future配合线程池,获取线程池执行线程的返回结果

    定义一个实现Callable接口的工作线程

    public class WorkThread implements Callable<Result> {
        
        public Result call() throws Exception {
            Thread.sleep(5000);
            Result result = new Result();
            result.setValue(Thread.currentThread().getName()+"线程执行完毕,输出结果");
            return result;
        }
    }

    主线程

    public class MainThread {
         public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
             ExecutorService taskPool = new ThreadPoolExecutor(5, 15, 1000, TimeUnit.MILLISECONDS,
                        new ArrayBlockingQueue<>(10), new ThreadPoolExecutor.CallerRunsPolicy());
             Future<Result> future = taskPool.submit(new WorkThread());
             System.out.println("线程池执行工作线程");
             Result result = future.get();//注意这里get操作是阻塞,future仍属于同步返回,主线程需要阻塞等待结果返回
             //result = future.get(3,TimeUnit.SECONDS);//设置阻塞超时时间
             System.out.println(result.getValue());
         }
    }

    Future与FutureTask实现方式基本类似,FutureTask其实是对Futue的进一步封装,通过上面的代码我们可以看到Future能够配合ExecutorService 线程池来获取线程执行的结果,使用起来也较为方便,同时可以设置获取结果的超时时间,避免长时间阻塞带来的问题,基本上能够满足大部分应用场景下的要求, 但Future获取结果的get方法是阻塞,本质上是个同步返回,如果希望获取结果所在线程不阻塞,需要引入其他模式相互配合,这个我们下面会说到。

    2、CompletionService

    CompletionService可以看作FutureTask的一个进阶版,通过FutureTask+阻塞队列的方式能够按照线程执行完毕的顺序获取线程执行结果,起到聚合的目的,这个其实跟CountDownLatch差不多,如果你需要执行的线程次数是固定的且需要等待执行结果全部返回后统一处理,可以使用CompletionService,下面我们通过示例代码进行演示

    同上先实现一个工作线程,这次我们为了能体现出结果输出的顺序,在工作线程内部定义一个编号,编号为偶数的线程阻塞一定时间

    public class WorkThread implements Callable<Result>{
        int num;//线程编号
        
        public WorkThread(int num) {
            this.num=num;
        }
        
        public Result call() throws InterruptedException {
            int count = num;
            if(count%2==0) {//编号为偶数的线程阻塞3秒钟
                Thread.sleep(3*1000);
            }
            Result result = new Result();
            result.setValue(num+"号线程执行完毕,输出结果");
            return result;
        }
    }

    主线程中启动十个线程

    public static void main(String[] args) throws InterruptedException, ExecutionException {
            
            ExecutorService exec = new ThreadPoolExecutor(10, 20, 1000, TimeUnit.MILLISECONDS,
                    new ArrayBlockingQueue<Runnable>(5), Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy());
            
            //定义一个阻塞队列
            BlockingQueue<Future<Result>> futureQueue =    new LinkedBlockingQueue<Future<Result>>();
            
            //传入ExecutorService与阻塞队列,构造一个completionService
            CompletionService<Result> completionService = new ExecutorCompletionService<Result>(
                    exec,futureQueue);
            
            for(int i=0;i<10;i++) {
                completionService.submit(new WorkThread(i));
            }
            
            for(int i=0;i<10;i++) {
                Result res = completionService.take().get();//注意阻塞队列take操作,如果获取不到数据时处于阻塞状态的
                System.out.println(new Date()+ "--"+res.getValue());
            }
        }
    }

    输出结果如下,可以看到奇数编号的线程结果优先返回,偶数编号的线程由于阻塞3秒后才输出返回结果,符合程序预期;

    Sun Apr 11 18:38:46 CST 2021--3号线程执行完毕,输出结果
    Sun Apr 11 18:38:46 CST 2021--1号线程执行完毕,输出结果
    Sun Apr 11 18:38:46 CST 2021--7号线程执行完毕,输出结果
    Sun Apr 11 18:38:46 CST 2021--9号线程执行完毕,输出结果
    Sun Apr 11 18:38:46 CST 2021--5号线程执行完毕,输出结果
    Sun Apr 11 18:38:49 CST 2021--2号线程执行完毕,输出结果
    Sun Apr 11 18:38:49 CST 2021--4号线程执行完毕,输出结果
    Sun Apr 11 18:38:49 CST 2021--0号线程执行完毕,输出结果
    Sun Apr 11 18:38:49 CST 2021--8号线程执行完毕,输出结果
    Sun Apr 11 18:38:49 CST 2021--6号线程执行完毕,输出结果

    上面主线程代码中的completionService.take().get()操作,当获取不到数据也就是当偶数编号线程休眠时仍然会产生阻塞, 其实我们只要对上面代码进行稍微改造就能避免主线程的阻塞,这也就引出了我们下面要说的生产者与消费者模式;

    四、生产者消费者模式

    上面我们列举的几种获取多线程执行结果的方式,都是通过不同技术方法来实现的,而生产者消费者模式本身跟你运用的技术实现没有太多关系,接触过多线程开发的同学应该都有所了解;

    生产者消费者模式如下图所示

    生产者消费者模式是一种能够解耦与同步生产线程、消费线程、数据集合的多线程设计模式,一个或一组生产者线程负责向数据队列中生产数据,也就是线程执行结果;另外一个或一组消费者线程负责消费处理数据队列中的数据,生产者线程与消费者线程相互之间并没有直接的关联,数据的交互都是通过数据队列,通过这种模式能够很好的在一定程度上解决多线程开发中存在线程同步与安全的问题,同时程序也会看起来更加清晰与方便理解;

    当然一个完善的生产者消费者模式我们需要考虑很多其他方面,  但最关键的还是以下两个要素:

    1、线程安全,生产者与消费者分别执行读写操作,特别是在多个生产线程与消费线程时,一定会存在数据读写的并发操作,所以数据队列一定要保证线程安全;

    2、生产与消费的协调,数据队列满时生产线程是否停止写入,数据队列空时消费线程是否停止消费,这里一方面需要结合你的应用场景,同时也是需要考虑不必要的性能浪费;

    下面看下基本的代码实现

    首先定义一个全局的数据队列,这里我用的JDK提供的阻塞队列ArrayBlockingQueue,这里同样也直接可以上面讲到的completionService,当然也可以用其他线程安全的数据集合或者自己定义实现,但要注意无论使用哪种都要注意上面的两个关键要素,平常使用中JDK封装的阻塞队列已经基本满足要求;

    public class Container {
        public static ArrayBlockingQueue<Result> arrayBlockingQueue = new ArrayBlockingQueue<>(100);//这里最好根据系统负载量评估一个阈值,避免OOM问题
    }

    生产者线程实现,队列数据插入时是采用put还是offer结合应用场景调整

    public class ProducerThread extends Thread {
        
        public void run() {    
            try {
                Thread.sleep(1000*3);//模拟程序执行
                Result result = new Result();
                result.setValue(Thread.currentThread().getName()+"线程执行完毕,输出结果");
                Container.arrayBlockingQueue.put(result);//超过阻塞队列最大阈值时阻塞,一直阻塞
    //            if(!Container.arrayBlockingQueue.offer(result, 5, TimeUnit.SECONDS)) {//规定时间内数据入队失败
    //                System.err.println("数据入队失败");
    //            }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
    }

    消费者线程实现,消费者线程是常驻线程,队列中没有数据时就线程阻塞

    public class ConsumerThread extends Thread {
        
        public void run() {
             while (!this.isInterrupted()) {
                 try {
                    Result result = Container.arrayBlockingQueue.take();//有数据就消费,没有就阻塞等待
                    System.out.println(result.getValue());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
             }
        }
    }

     主线程中同时启动生产线程与消费线程

    public class MainThread  {
        public static void main(String[] args) {
            
            ExecutorService exec = new ThreadPoolExecutor(10, 20, 1000, TimeUnit.MILLISECONDS,
                    new ArrayBlockingQueue<Runnable>(5), Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy());
            
            for(int i=0;i<100;i++) {//使用线程池模拟生成者生产数据
                exec.execute(new ProducerThread());
            }
            
            for(int i=0;i<2;i++) {//启动两个消费者线程
                new ConsumerThread().start();
            }
        }
    }

    消费者线程中会轮询获取生产者线程执行并放到阻塞队列中的结果

    pool-1-thread-13线程执行完毕,输出结果
    pool-1-thread-2线程执行完毕,输出结果
    pool-1-thread-1线程执行完毕,输出结果
    pool-1-thread-10线程执行完毕,输出结果
    pool-1-thread-9线程执行完毕,输出结果
    pool-1-thread-15线程执行完毕,输出结果
    pool-1-thread-4线程执行完毕,输出结果
    pool-1-thread-5线程执行完毕,输出结果
    pool-1-thread-8线程执行完毕,输出结果
    pool-1-thread-12线程执行完毕,输出结果
    pool-1-thread-16线程执行完毕,输出结果
    .....................................................
    .....................................................

    生产者消费者模式是程序开发当中一种十分常见且易于理解与掌握的开发设计模式,且适用场景广泛,希望大家都能够深入理解与掌握

    五、异步回调

    上面列举的获取线程执行结果的方法都存在一个共性的问题,就是在等待结果的返回过程中,主线程或者消费者线程都是需要阻塞或轮询等待的,但在一些应用场景下我们是希望线程执行的过程中,程序该干嘛干嘛,继续向下执行,等到结果返回了再通过回调来通知,这就是异步回调的必要性。实现异步回调思路我这里列举两种,一种是多线程与回调,第二种JDK1.8中新加入了一个实现类CompletableFuture,通过这两种都能够实现异步获取线程执行结果的目标

    1、多线程与回调

    这里其实是在多线程中通过回调的方式把结果返回的方式,我们看下具体实现

    首先声明一个回调接口

    public interface CallBack {
    
        void notice(Result result);
    
    }

    定义工作线程,在构造函数中传入回调接口的实现对象

    public class WorkThread implements Runnable{
        int num;//线程编号
        
        CallBack callBack;
        
        public WorkThread(CallBack callBack, int num) {
            this.num=num;
            this.callBack = callBack;
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                Thread.sleep((10-num)*1000);//模拟程序运行时间,倒序输出
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Result result = new Result();
            result.setValue(num+"号线程执行完毕,输出结果");
            callBack.notice(result);
        }
    }

    调用方及回调方法具体实现

    public class MainThread implements CallBack {
        
        public void run(int num) {
             WorkThread workThread =  new WorkThread(this,num);
             new Thread(workThread).start();
        }
    
        @Override
        public void notice(Result result) {
            System.out.println("返回结果:"+result.getValue());    
        }
    
    }

    程序执行及输出

    public class App {
         public static void main(String[] args) {
             MainThread mainThread = new MainThread();
             for(int i=0;i<10;i++) {
                 mainThread.run(i);
             }
             System.out.println("继续执行,表示异步操作");
         }
    }

    输出结果

    继续执行,表示异步操作
    返回结果:9号线程执行完毕,输出结果
    返回结果:8号线程执行完毕,输出结果
    返回结果:7号线程执行完毕,输出结果
    返回结果:6号线程执行完毕,输出结果
    返回结果:5号线程执行完毕,输出结果
    返回结果:4号线程执行完毕,输出结果
    返回结果:3号线程执行完毕,输出结果
    返回结果:2号线程执行完毕,输出结果
    返回结果:1号线程执行完毕,输出结果
    返回结果:0号线程执行完毕,输出结果

    多线程+回调也是一种常见的异步回调实现方式,但需要注意的是我们自己手动实现异步回调时还是有很多细节需要考虑完善的,如异常、超时、线程开辟与管理等,这里就不再过多的展开。

    2、CompletableFuture

    JDK1.8中新增的CompletableFuture中通过函数式的编程方法提供了等同于异步回调的能力,下面我们进行具体实现

    工作线程

    public class WorkThread {
    
        public static Result call(int num) throws InterruptedException  {
            Thread.sleep(5*1000);//模拟程序执行时间    
            Result result = new Result();
            result.setValue(String.valueOf(num));
            return result;
        }
    }

    主线程

    public class MainThread {
    
         public static void main(String[] args) {
                List<String> reslist = new ArrayList<String>();
                ExecutorService exs = Executors.newFixedThreadPool(10);//定义一个线程池
                List<CompletableFuture<Result>> futureList = new ArrayList<>();
                try {
                    for(int i=0;i<10;i++) {
                        final int k = i;
                        CompletableFuture<Result> future=CompletableFuture.supplyAsync(()->{
                            try {
                                return WorkThread.call(k);
                            } catch (InterruptedException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            }
                            return null;
                        },exs).thenApply(e->mul(e)).whenComplete((v, e) -> {//thenApply 里面执行就是回调函数CallBack
                                        System.out.println("线程"+k+"完成! 结果:"+v.getValue()+",异常 :"+e+","+new Date());
                                        reslist.add(v.getValue());
                                    });
                        
                        futureList.add(future);//聚合返回结果
                    }
                    System.out.println("继续执行,表示异步操作");
    
    
                }catch (Exception e) {
                    // TODO: handle exception
                }
            }
            
            
            public static Result mul(Result result){
                try {
                    Integer val = Integer.valueOf(result.getValue())*2;
                    result.setValue(val.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return result;
            }
    }

    输出结果如下,可以看到主线程没有等待线程执行结果返回,继续向下执行

    直接输出,标识异步操作
    线程9完成! 结果:18,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程2完成! 结果:4,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程5完成! 结果:10,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程1完成! 结果:2,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程6完成! 结果:12,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程3完成! 结果:6,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程0完成! 结果:0,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程4完成! 结果:8,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程8完成! 结果:16,异常 :null,Sun Apr 18 17:27:29 CST 2021
    线程7完成! 结果:14,异常 :null,Sun Apr 18 17:27:29 CST 2021

    CompletableFuture中提供了丰富的API实现,提供了诸如聚合计算等一整套功能,这里就不做太多表述,有兴趣的小伙伴可以去多做了解。

     

    展开全文
  • 【多线程】获取多线程执行结果

    千次阅读 2020-04-02 12:52:12
    1. 观察者模式结合线程实现获取线程执行结果线程开发中,我们没办法获取线程执行完成后的结果,但是当我们利用观察者模式的时候我们就可以获取线程的执行结果 2.具体实现 假设目前有一批id需要查询并...

    1. 观察者模式结合多线程实现获取线程执行结果

    在多线程开发中,我们没办法获取线程执行完成后的结果,但是当我们利用观察者模式的时候我们就可以获取到多线程的执行结果

    2.具体实现

    假设目前有一批id需要查询并需要获得查询结果, 利用多线程结合设计模式实现

    2.1 LifeCycleListener

    public interface LifeCycleListener {
        void onEvent(ObserverableRunnable.RunnableEvent event);
    }
    

    2.2 ObserverableRunnable

    
    public abstract class ObserverableRunnable implements Runnable{
    
        /**
         * 监听这
         */
        final protected LifeCycleListener listener;
    
        public ObserverableRunnable(LifeCycleListener listener) {
            this.listener = listener;
        }
    
    
        public void notifyChange(final RunnableEvent event) {
            listener.onEvent(event);
        }
    
        public enum RunnableState {
            RUNNING, ERROR, DONE;
        }
    
        /**
         * 内部类尽量都是静态的,不然作为成员对象每次创建对象都会复制
         */
        public static class RunnableEvent {
    
            private final RunnableState state;
            private final Thread thread;
            private final Throwable cause;
    
    
            public RunnableEvent(RunnableState state, Thread thread, Throwable cause) {
                this.state = state;
                this.thread = thread;
                this.cause = cause;
            }
    
            public RunnableState getState() {
                return state;
            }
    
            public Thread getThread() {
                return thread;
            }
    
            public Throwable getCause() {
                return cause;
            }
        }
    }
    
    

    2.3 ThreadLifeCycleObserver

    package com.gy.observer;
    
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.IntStream;
    
    /**
     * 模拟当前类使用多线程需要去处理一批id,并拿到结果
     * 1. 创建处理方法并通过ObserverableRunnable去执行任务
     * 2. 当ObserverableRunnable吧任务执行完成后提醒当前类做完了
     * 3. 拿到返回值处理
     */
    public class ThreadLifeCycleObserver implements LifeCycleListener {
    
    
        private Object LOCK = new Object();
    
        private void concurrentQuery(List<Integer> ids) {
            if (ids.size() == 0 && ids.isEmpty())
                return;
    
            ids.stream().forEach((id)->{
                new Thread(new ObserverableRunnable(this) {
                    @Override
                    public void run() {
                        try {
                            notifyChange(new RunnableEvent(RunnableState.RUNNING,  Thread.currentThread(), null));
                            System.out.printf("query for id = %s\n", id);
                            Thread.sleep(1000);
                            notifyChange(new RunnableEvent(RunnableState.DONE,  Thread.currentThread(), null));
                        } catch (InterruptedException e) {
                            notifyChange(new RunnableEvent(RunnableState.ERROR,  Thread.currentThread(), e));
                        }
                    }
                }).start();
            });
        }
    
    
    
        /**
         * 这个方法可能是多个线程在回调所以需要使用同步锁
         * @param event
         */
        @Override
        public void onEvent(ObserverableRunnable.RunnableEvent event) {
            synchronized (LOCK) {
                System.out.println(event.getThread().getName() + " == " + event.getState());
            }
        }
    
    
        public static void main(String[] args) {
            ThreadLifeCycleObserver threadLifeCycleObserver = new ThreadLifeCycleObserver();
            threadLifeCycleObserver.concurrentQuery(Arrays.asList(1, 2, 3));
        }
    }
    
    
    展开全文
  • 在工作中是否存在这样的场景,多个线程提交执行,你不想全部线程执行结束了获取结果,而是有线程完成返回结果获取消费。本文提供该场景的工具,可以直接用哦。 Maven依赖 其实要不要无所谓。主要是为了方便...

    目录

    前言

    Maven依赖

    代码

    总结


    前言

    在工作中是否存在这样的场景,多个线程提交执行,你不想全部线程执行结束了获取结果,而是有线程完成返回结果就获取消费。本文提供该场景的工具类,可以直接用哦。

    Maven依赖

    其实要不要无所谓。主要是为了方便。

            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.7.15</version>
            </dependency>

    代码

    不废话,上代码。

    package com.hy.csdn.tools;
    
    import cn.hutool.core.thread.ThreadUtil;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.*;
    import java.util.function.Consumer;
    
    /**
     * @author huyi
     * @date 2021/11/1 下午2:22
     */
    public class ThreadPriorityUtil {
      private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(100);
    
        /**
         * 提交多个任务
         * @param tasks 任务
         * @param consumer 结果消费
         * @param <T> 泛型
         */
      public static <T> void submit(List<Callable<T>> tasks, Consumer<T> consumer) {
        CompletionService<T> completionService = new ExecutorCompletionService<>(EXECUTOR_SERVICE);
        tasks.forEach(completionService::submit);
        tasks.forEach(
            x -> {
              try {
                consumer.accept(completionService.take().get());
              } catch (InterruptedException e) {
                e.printStackTrace();
              } catch (ExecutionException e) {
                e.printStackTrace();
              }
            });
      }
    
      public static void destroy() {
        System.out.println("摧毁线程池");
        EXECUTOR_SERVICE.shutdown();
      }
    
      public static void main(String[] args) {
        // 启动3个线程执行试试看
        List<Callable<Integer>> tasks =
            Arrays.asList(
                () -> {
                  try {
                    TimeUnit.SECONDS.sleep(30);
                    System.out.println("task 30 completed");
                  } catch (InterruptedException e) {
                    e.printStackTrace();
                  }
                  return 30;
                },
                () -> {
                  try {
                    TimeUnit.SECONDS.sleep(10);
                    System.out.println("task 10 completed");
                  } catch (InterruptedException e) {
                    e.printStackTrace();
                  }
                  return 10;
                },
                () -> {
                  try {
                    TimeUnit.SECONDS.sleep(20);
                    System.out.println("task 20 completed");
                  } catch (InterruptedException e) {
                    e.printStackTrace();
                  }
                  return 20;
                });
    
        ThreadPriorityUtil.submit(tasks, x -> System.out.println("回调结果:" + x));
    
        ThreadUtil.sleep(40000L);
        ThreadPriorityUtil.destroy();
      }
    }
    

    执行看看

    OK,先执行结束的线程,先消费。

    总结

    一个姑娘,如果有被人喜欢,而且那个人喜欢的干干净净,怎么都是一件美好的事情。

    如果本文对你有帮助的话,不要吝啬你的赞,狠狠的甩给我。

     

    展开全文
  • Python 之获取多线程返回结果

    千次阅读 2019-01-06 16:11:11
    然而,在经过我的多番尝试、以及网上各种博客显示,在 Python3 中是无法获得单个线程中返回的结果的,因此我们需要定义一个类来实现这个过程,这个类的定义如下: class MyThread(threading.Thread): def __init__...
  • 最近在处理一个 `Python` 局部变量的作用域问题时发现有些奇怪,想起了之前常写的 `Lua` 脚本,于是想写个函数测试一下,结果发现短短的十几行代码出现了多个错误,这可是我写了近三年的代码啊,才放下半年就记不清...
  • 关键在于: applicationContext.getBeansOfType(ChartService.class);... 获得Map对象的key为实现的名称如:chartSimpleServiceImpl 获得Map对象的value为实现对象如:com.read.data.cms.service.impl.Char...
  • Python多种方法获取多线程返回值

    万次阅读 多人点赞 2019-07-02 21:23:39
    近段时间,工作上需要用到多线程,并且要获取多线程的返回值,python多线程一般使用threading模块,但threading模块有问题,无法返回线程里面运行的结果,我通过三种方法讲解如何获取多线程的返回值。 一、通过...
  • 如何获取某个的所有子类

    万次阅读 2019-11-14 09:46:16
    如何获取某个的所有子类引言解决方案(获取基础与IAnimal的所有子类)总结 引言 在我们写工厂的时候,可能会根据不同的类型(type)生成不同的对象。但在工厂初始化的时候,我们需要将某个类型的所有全部初始化...
  • getActualTypeArguments()返回一个Type数组,之所以返回Type数组,是因为一个类上有可能出现多个泛型,比如:Map,String> */ Type [] actualTypes = pt.getActualTypeArguments(); System.out.println(actualTypes...
  • 在运行状态中,对任意一个类都有获取个类的所有属和方法,对于任意一个对象,都能调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。...
  • Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实现,可以来进行...在途中遇到一问题,那就是虽然能异步获取结果,但是Future的结果需要通过isdone来判断是否有结
  • 1、加载多个配置文件 需求描述: 项目结构: 详细配置: 配置yml 测试: 2、获取配置文件中的数组值 需求描述: 实现方式: 测试: 1、加载多个配置文件 需求描述: 项目中需要根据功能配置多个配置...
  • 因为平时用反射很少,之前一次面试被问到反射这块的一个问题,很简单,当时给了个...这个问题我想到的就是反射获取个类的所有方法,然后去找它的参数(当时不确定有方法能获取参数类型),在反过来调用这个方法。然后
  • 为了保证系统响应迅速,需要寻找一种方法能够使调取接口能够异步执行,而Java正好提供了类似的方法,在java.util.concurrent中包含了Future相关的,运用其中的一些可以进行异步计算,以减少主线程的等待时间。...
  • 一、C#获取对象的类型方式 方式1.所有隐式继承自Object,然而Object中的GetType()就可以获取当前对象的,对应的类型 // // 摘要: // 获取当前实例的 System.Type。 // // 返回结果: // 当前实例的...
  • 但实际上第一任务A和第二任务B互不影响, 我们可以使用线程的方法,将任务A和任务B并行执行,最后将两任务的执行结果相加。那这样怎么用java实现呢? 引言: 在之前的 java线程入门 中介绍了java创建...
  • Java获取类或接口上的泛型类型T方法

    万次阅读 2019-09-19 16:03:41
    获取类或接口上的泛型类型Class<?>,然后对这类型进行数据处理,至于怎么处理,还要看实际的应用场景。本篇讲述如何获取类或接口的泛型类型(参数化类型ParameterizedType)。 实例 1.定义泛型接口 public...
  • @RequestBody接收前端传来的多个参数

    万次阅读 2020-07-13 21:39:45
    在使用ajax发送请求时,如果发送的JSON数据是一个类中的不同属性,在Controller方法中使用@RequestBody会直接封装进该类中 例如: 前端部分代码 JavaScript 1 <script language="JavaScript"> 2 ...
  • 反射获取类或对象属性和值

    千次阅读 2019-05-08 18:36:30
    由于部分常量配置在接口而非枚举中,当我们需要通过属性名去获取具体接口中常量对应的值时,或是要获取该接口中所有常量名和对应值的键值对集合,显得有些麻烦或是无从下手,故这里封装一通用的工具来满足此类...
  • 1、需要异步线程执行,而且需要获取到线程执行返回的结果。 2、如果执行过程异常,可以按照自定义方式消费异常信息。 如果只是单纯的使用Callable可以实现,本文提供更加优雅的工具。 Maven依赖 <...
  • 如何让一个函数返回多个返回值

    万次阅读 多人点赞 2018-07-29 20:26:47
    以一题目为例: 要求用户使用一整数指出自己的身高(单位为英寸),然后将身高转化为英尺和英寸。 方法一: 利用结构体,注意函数定义一定要用结构体来定义 struct trans { int chi; int cun; }; trans ...
  • Java获取类、方法、属性上的注解

    万次阅读 多人点赞 2017-04-28 21:03:15
    获取某个的注解有3方法Class.getAnnotations()、Class.getAnnotation(Class< A > annotationClass)、Class.getDeclaredAnnotations(); 获取某个方法的注解,跟一样,也是3中方式
  • 这篇开始学习Thread相关方法,先来看看给线程设置名称和获取名称的方法。打开Thread API文档,找到getName()和setName()方法。我们先来看看获取线程名称方法,然后看看设置线程名称方法。 1.获取线程名称getName...
  • java8 多个list对象用lambda求差集操作

    千次阅读 2021-03-22 15:55:45
    业务场景:调用同步接口获取当前全部数据库已存在部分账户信息,因此需要筛选同步接口中已存在本地的帐户。调用接口获取的数据集合List list = response.getData().getItwww.cppcns.comemsnTzXmIBif();本地查询出来...
  • for循环使用线程 并查看执行结果

    万次阅读 2020-02-16 18:10:20
    } } 运行结果 ExecutorCompletionService实现了CompletionService接口, 在CompletionService接口中定义了如 下这些方法: Future submit(Callable task):提交一Callable类型任务 ,并返回该任务执行结果关联 的...
  • 深入理解Java加载器(ClassLoader)

    万次阅读 多人点赞 2017-06-26 09:34:08
    这便是类加载的5个过程,而类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例,在虚拟机提供了3种类加载器,引导(Bootstrap)类加载器...
  • Python 获取多线程返回值的两种方式

    万次阅读 多人点赞 2019-06-16 18:14:41
    1. 通过复写Thread,自定义一get_result()方法 from threading import Thread # _sum = 0 def cal_sum(begin, end): # global _sum _sum = 0 for i in range(begin, end + 1): _sum += i return ...
  • 在hibernate开发中,经常会遇到表查询,那么当查询出来得这个集合不与我们得任何一个类有关系,我们如何获取呢? 假设有两个bean,一个叫User,另一个叫Order User 字段:userId,userName,telephone,address ...
  • 最近项目中用到获取手机IMEI,IMSI以及MAC,在此记录一下,方便你我他。。。 那么什么时候会用到这些东西呢? LZ 个人认为,如果项目当中需要对当前使用用户设备做唯一标识时(证明这是你用的)可以使用这种方式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,447,396
精华内容 578,958
关键字:

如何获取多个类的结果