精华内容
下载资源
问答
  • 2019-08-22 14:54:50

    代码如下

    package com.thread.threadlocal;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    import java.util.concurrent.*;
    
    public class MainTest {
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            Set<Callable<String>> callableSet = new HashSet<>();
            callableSet.add(() -> "task1");
            callableSet.add(() -> "task2");
            callableSet.add(() -> "task3");
            List<Future<String>> list = executorService.invokeAll(callableSet);
            for(Future<String> stringFuture : list) {
                System.out.println("future task: " + stringFuture.get());
            }
            TimeUnit.MILLISECONDS.sleep(500);
            executorService.shutdown();
        }
    
    }
    

    执行结果如下

    future task: task2
    future task: task1
    future task: task3
    
    更多相关内容
  • Java 使用线程池执行多个任务的示例

    千次阅读 2021-03-12 17:19:13
    这篇文章主要介绍了Java 使用线程池执行多个任务的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下 在执行一系列带有IO操作(例如下载文件),且互不相关的异步任务时,采用多线程可以很极大的提高...

    这篇文章主要介绍了Java 使用线程池执行多个任务的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下

    在执行一系列带有IO操作(例如下载文件),且互不相关的异步任务时,采用多线程可以很极大的提高运行效率。线程池包含了一系列的线程,并且可以管理这些线程。例如:创建线程,销毁线程等。本文将介绍如何使用Java中的线程池执行任务。

    1 任务类型

    在使用线程池执行任务之前,我们弄清楚什么任务可以被线程池调用。按照任务是否有返回值可以将任务分为两种,分别是实现Runnable的任务类(无参数无返回值)和实现Callable接口的任务类(无参数有返回值)。在打代码时根据需求选择对应的任务类型。

    1.1 实现Runnable接口的类

    多线程任务类型,首先自然想到的就是实现 Runnable 接口的类,Runnable接口提供了一个抽象方法run,这个方法无参数,无返回值。例如:

    Runnable task = new Runnable() {
      @Override
      public void run() {
        System.out.println("Execute task.");
      }
    };
    

    或者Java 8 及以上版本更简单的写法

    Runnable task = ()->{
      System.out.println("Execute task.");
    };
    

    1.2 实现Callable接口的类
    于Runnable一样Callable也只有一个抽象方法,不过该抽象方法有返回值。在实现该接口的时候需要制定返回值的类型。例如:

    Callable<String> callableTask = ()-> "finished";
    

    于Runnable一样Callable也只有一个抽象方法,不过该抽象方法有返回值。在实现该接口的时候需要制定返回值的类型。例如:

    Callable<String> callableTask = ()-> "finished";
    

    2 线程池类型

    java.util.concurrent.Executors 提供了一系列静态方法来创建各种线程池。下面例举出了主要的一些线程池及特性,其它未例举线程池的特性可由下面这些推导出来。

    2.1 线程数固定的线程池 Fixed Thread Pool

    顾名思义,这种类型线程池线程数量是固定的。如果线程数量设置为n,则任何时刻该线程池最多只有n个线程处于运行状态。当线程池中处于饱和运行状态时,再往线程池中提交的任务会被放到执行队列中。如果线程池处于不饱和状态,线程池也会一直存在,直到ExecuteService 的shutdown方法被调用,线程池才会被清除。

    // 创建线程数量为5的线程池。
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    

    2.2 可缓存的线程池 Cached Thread Pool
    这种类型的线程池初始大小为0个线程,随着往池里不断提交任务,如果线程池里面没有闲置线程(0个线程也表示没有闲置线程),则会创建新的线程,保证没有任务在等待;如果有闲置线程,则复用闲置状态线程执行任务。处于闲置状态的线程只会在线程池中缓存60秒,闲置时间达到60s的线程会被关闭并移出线程池。在处理大量短暂的(官方说法:short-lived)异步任务时可以显著得提供程序性能。

    //创建一个可缓存的线程池 
    ExecutorService executorService = Executors.newCachedThreadPool();
    

    2.3 单线程池
    这或许不能叫线程池了,由于它里面的线程永远只有1个,而且自始至终都只有1个(为什么说这句话,因为要和 Executors.newFixedThreadPool(1) 区别开来),所以还是叫它“单线程池把”。你尽可以往单线程池中添加任务,但是每次只执行1个,且任务是按顺序执行的。如果前面的任务出现了异常,当前线程会被销毁,但1个新的线程会被创建用来执行后面的任务。以上这些和线程数只有1个的线程Fixed Thread Pool一样。两者唯一不同的是, Executors.newFixedThreadPool(1) 可以在运行时修改它里面的线程数,而 Executors.newSingleThreadExecutor() 永远只能有1个线程。

    //创建一个单线程池
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    

    2.4 工作窃取线程池
    扒开源码,会发现工作窃取线程池本质是 ForkJoinPool ,这类线程池充分利用CPU多核处理任务,适合处理消耗CPU资源多的任务。它的线程数不固定,维护的任务队列有多个,当一个任务队列完成时,相应的线程会从其它的任务队列中窃取任务执行,这也意味着任务的开始执行顺序并和提交顺序相同。如果有更高的需求,可以直接通过ForkJoinPool获取线程池。

    //创建一个工作窃取线程池,使用CPU核数等于机器的CPU核数
    ExecutorService executorService = Executors.newWorkStealingPool();
    
    //创建一个工作窃取线程池,使用CPU 3 个核进行计算,工作窃取线程池不能设置线程数
    ExecutorService executorService2 = Executors.newWorkStealingPool(3);
    

    2.5 计划任务线程池
    计划任务线程池可以按计划执行某些任务,例如:周期性的执行某项任务。

    // 获取一个大小为2的计划任务线程池
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
    // 添加一个打印当前线程信息计划任务,该任务在3秒后执行
    scheduledExecutorService.schedule(() -> { System.out.println(Thread.currentThread()); }, 3, TimeUnit.SECONDS);
    // 添加一个打印当前线程信息计划任务,该任务在2秒后首次执行,之后每5秒执行一次。如果任务执行时间超过了5秒,则下一次将会在前一次执行完成之后立即执行
    scheduledExecutorService.scheduleAtFixedRate(() -> { System.out.println(Thread.currentThread()); }, 2, 5, TimeUnit.SECONDS);
    // 添加一个打印当前线程信息计划任务,该任务在2秒后首次执行,之后每次在任务执行之后5秒执行下一次。
    scheduledExecutorService.scheduleWithFixedDelay(() -> { System.out.println(Thread.currentThread()); }, 2, 5, TimeUnit.SECONDS);
    // 逐个清除 idle 状态的线程
    scheduledExecutorService.shutdown();
    // 阻塞,在线程池被关调之前代码不再往下走
    scheduledExecutorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
    

    3 使用线程池执行任务

    前面提到,任务类型分为有返回值和无返回值的类型,这里的调用也分为有返回值调用和无返回值的调用。

    3.1 无返回值任务的调用

    如果是无返回值任务的调用,可以用execute或者submit方法,这种情况下二者本质上一样。为了于有返回值任务调用保持统一,建议采用submit方法。

    //创建一个线程池
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    
    //提交一个无返回值的任务(实现了Runnable接口)
    executorService.submit(()->System.out.println("Hello"));
    
    executorService.shutdown();
    executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
    

    如果有一个任务集合,可以一个个提交。

    //创建一个线程池
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    List<Runnable> tasks = Arrays.asList(
        ()->System.out.println("Hello"),
        ()->System.out.println("World"));
    
    //逐个提交任务
    tasks.forEach(executorService::submit);
    
    executorService.shutdown();
    executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
    

    3.2 有返回值任务的调用
    有返回值的任务需要实现Callable接口,实现的时候在泛型位置指定返回值类型。在调用submit方法时会返回一个Future对象,通过Future的方法get()可以拿到返回值。这里需要注意的是,调用get()时代码会阻塞,直到任务完成,有返回值。

    ExecutorService executorService = Executors.newFixedThreadPool(2);
    Future<String> future = executorService.submit(()->"Hello");
    System.out.println(future.isDone());//false
    String value = future.get();
    System.out.println(future.isDone());//true
    System.out.println(value);//Hello
    

    如果要提交一批任务,ExecutorService除了可以逐个提交之外,还可以调用invokeAll一次性提交,invokeAll的内部实现其实就是用一个循环逐个提交任务。invokeAll返回的值是一个Future List。

    ExecutorService executorService = Executors.newFixedThreadPool(2);
    List<Callable<String>> tasks = Arrays.asList(()->"Hello", ()->"World");
    List<Future<String>> futures = executorService.invokeAll(tasks);
    

    invokeAny方法也很有用,线程池执行若干个实现了Callable的任务,然后返回最先执行结束的任务的值,其它未完成的任务将被正常取消掉不会有异常。如下代码不会输出“Hello”

    ExecutorService executorService = Executors.newFixedThreadPool(2);
    List<Callable<String>> tasks = Arrays.asList(
        () -> {
          Thread.sleep(500L);
          System.out.println("Hello");
          return "Hello";
        }, () -> {
          System.out.println("World");
          return "World";
        });
    String s = executorService.invokeAny(tasks);
    System.out.println(s);//World
    

    输出:

    World
    World
    

    另外,在查看ExecutorService源码时发现它还提供了一个方法 Future submit(Runnable task, T result); ,可以通过这个方法提交一个实现了Runnable接口的任务,然后有返回值,而Runnable接口中的run方法时没有返回值的。那它的返回值是哪来的呢?其实问题在于该submit方法后面的一个参数,这个参数值就是返回的值。调用submit方法之后,有一通操作,然后直接把result参数返回了。

    ExecutorService executorService = Executors.newFixedThreadPool(1);
    Future<String> future = executorService.submit(() -> System.out.println("Hello"), "World");
    System.out.println(future.get());//输出:World
    

    在利用多线程处理任务时,应该根据情况选择合适的任务类型和线程池类型。如果无返回值,可以采用实现Runnable或Callable接口的任务;如果有返回值,应该使用实现Callable接口的任务,返回值通过Future的get方法取到。选用线程池时,如果只用1个线程,用单线程池或者容量为1的固定容量线程池;处理大量short-live任务是,使用可缓存的线程池;若要有计划或者循环执行某些任务,可以采用计划任务线程池;如果任务需要消耗大量的CPU资源,应用工作窃取线程池。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持

    展开全文
  • public R<String>... // 线程开始 分析指标 ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2)); Callable tk1 ...
        public R<String> tgFx(){
            long b = System.currentTimeMillis();
    
            // 多线程开始 分析指标
            ThreadPoolExecutor executor = new ThreadPoolExecutor(8, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2));
            Callable tk1 =()->{
                long l = System.currentTimeMillis();
                String res = tgBasicInfoService.addTgBasicInfoAll();
                long l1 = System.currentTimeMillis() - l;
                System.out.println("<<<====线程【1】执行完成  耗时"+ l1+ " 毫秒" );
                return 1;
            };
    
            Callable tk2 =()->{
                long l = System.currentTimeMillis();
                tgBasicInfoService.queryPoUserRap();
                long l1 = System.currentTimeMillis() - l;
                System.out.println("<<<====线程【2】执行完成  耗时"+ l1+ " 毫秒" );
                return 1;
            };
    
            Callable tk3 =()->{
                long l = System.currentTimeMillis();
                tgBasicInfoService.queryAllTg96Load();
                long l1 = System.currentTimeMillis() - l;
                System.out.println("<<<====线程【3】执行完成  耗时"+ l1+ " 毫秒" );
                return 2;
            };
    
    
            Callable tk4 =()->{
                long l = System.currentTimeMillis();
                tgBasicInfoService.insertExpansionTg();
                long l1 = System.currentTimeMillis() - l;
                System.out.println("<<<====线程【4】执行完成  耗时"+ l1+ " 毫秒" );
                return 2;
            };
    
    
            List tasks = new ArrayList<>();
            tasks.add(tk1);
            tasks.add(tk2);
            tasks.add(tk3);
            tasks.add(tk4);
    
            long l2 = System.currentTimeMillis();
            long d = l2 - b;
    
            try {
                executor.invokeAll(tasks);
                return R.data("++++++++++++++++计算完成+++++++++++++++耗时==>"+CalculateUtils.div(String.valueOf(d),"1000",2)+"秒");
            } catch (InterruptedException e) {
                e.printStackTrace();
                return R.data(e.getMessage());
            }finally {
                executor.shutdown();
            }
        }
    
    展开全文
  • java线程池处理并发,所有进程执行完后再统一处理结果线程池配置类线程并行demo 线程池配置类 import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation....
  • 使用线程池执行多线程需要如下几条件 首先是一线程池,线程池包含一些初始化数据,包含队列大小,核心线程数,最大线程数。 然后是一实现了 runnable的任务,将该任务当如到线程池中进行执行。 线程池...

    使用线程池执行多线程需要如下几个条件

    首先是一个线程池,线程池包含一些初始化数据,包含队列大小,核心线程数,最大线程数。

    然后是一个实现了 runnable的任务,将该任务当如到线程池中进行执行。

     

    线程池配置:

    public class ThreadPoolManager<T> {
    
        /**
         * 根据cpu的数量动态的配置核心线程数和最大线程数
         */
        private static final int CPU_COUNT         = Runtime.getRuntime().availableProcessors();
    
        /**
         * 核心线程数 = CPU核心数 + 1
         */
        private static final int CORE_POOL_SIZE    = CPU_COUNT + 1;
    
        /**
         * 线程池最大线程数 = CPU核心数 * 2 + 1
         */
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    
        /**
         * 非核心线程闲置时超时1s
         */
        private static final int KEEP_ALIVE        = 1;
    
    
        private ThreadPoolExecutor executor;
    
    
    
        private ThreadPoolManager() {
    
        }
    
        private static ThreadPoolManager sInstance;
    
        public synchronized static ThreadPoolManager getsInstance() {
            if (sInstance == null) {
                sInstance = new ThreadPoolManager();
            }
            return sInstance;
        }
    
    
        /**
         * 开启一个无返回值的线程
         * @param r
         */
        public void execute(Runnable r) {
            if (executor == null) {
                /**
                 * corePoolSize:核心线程数
                 * maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
                 * keepAliveTime:非核心线程闲置时间超时时长
                 * unit:keepAliveTime的单位
                 * workQueue:等待队列,存储还未执行的任务
                 * threadFactory:线程创建的工厂
                 * handler:异常处理机制
                 *
                 */
                executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
                        KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000),
                        Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
            }
            // 把一个任务丢到了线程池中
            executor.execute(r);
        }
    
        /**
         * 开启一个有返回结果的线程
         * @param r
         * @return
         */
        public Future<T> submit(Callable<T> r) {
            if (executor == null) {
                /**
                 * corePoolSize:核心线程数
                 * maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
                 * keepAliveTime:非核心线程闲置时间超时时长
                 * unit:keepAliveTime的单位
                 * workQueue:等待队列,存储还未执行的任务
                 * threadFactory:线程创建的工厂
                 * handler:异常处理机制
                 *
                 */
                executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
                        KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20),
                        Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
            }
            // 把一个任务丢到了线程池中
            return executor.submit(r);
        }
    
        /**
         * 把任务移除等待队列
         * @param r
         */
        public void cancel(Runnable r) {
            if (r != null) {
                executor.getQueue().remove(r);
            }
        }
    
    }

    2. 然后 新建一个任务类,实现 runnable 接口,重写run方法

    public class ConverterTask implements Runnable {
    
        
    
    
        @Override
        public void run() {
            //自己的业务逻辑,调用需要并发的方法
            //todo
        }
    }
    

    这样就可以简单的模拟一个线程池执行多线程的案例

    展开全文
  • Java线程池并发执行多个任务

    万次阅读 多人点赞 2017-06-28 23:14:11
    Java在语言层面提供了线程的支持,线程池能够避免频繁的线程创建和销毁的开销,因此很时候在项目当中我们是使用线程池去完成线程的任务。 Java提供了Executors 框架提供了一些基础的组件能够轻松的完成...
  • 主要给大家介绍了关于Spring Boot中配置定时任务、线程池线程池执行的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • 一个线程池执行多个任务

    千次阅读 2016-09-02 15:52:25
    今天写了些代码,测试了一下多个线程来执行多个任务的的情况,线程放在一个线程池里进行管理。 线程的数量控制在10个(当然可以指定线程池里的线程数量);任务的数量不做限制。  下面贴出代码,以备用时之需...
  • 其实线程处理的方式有很线程池,自定义线程等等,但是需要同时执行,所以这里线程池和CountDownLatch这类来进行处理 其实思路很简单,首先通过线程池划分好线程明细,然后通过线程池的submit进行处理,...
  • 主要介绍了Java判断线程池线程是否执行完毕,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 1.调用线程池的excutor()方法执行任务,如果有异常,线程终止,等待垃圾回收,并在下一次执行任务时,创建新的线程。 2.调用submit()方法执行任务,如果有异常,作为结果返回,在结果Future调用get()方法时抛出,...
  • 主要介绍了SpringBoot 任务并行+线程池处理的实现,小编觉得挺不错的,现在分享给大家,也给大家做参考。一起跟随小编过来看看吧
  • 用线程池+ FutureTask将1个查询拆分成多个查询 由于FutureTask仅执行1次run()的特性(即使有多次调用也只执行1次),避免了重复查询的可能。而且多任务异步执行也能提高接口响应速度。 若对FutureTask仅执行1次run...
  • (由于线程是在不同的时候执行数据),假如执行线程池后,在执行主线程,这就涉及到线程优先级。所以会比较蛮烦。 import java.util.*; import java.util.concurrent.CountDownLatch; public class Te...
  • 创建单个线程的线程池对象2.2、第二种: 创建固定数量的线程池(指定核心线程数数量)2.3、第三种:创建一按照计划执行线程池2.4、第四种:创建一自动增长的线程池总结 前言 上一篇文章讲了线程的三种实现 ...
  • Java线程池执行流程(源码解读) 一.背景介绍 java中,如果每请求都创建一新线程,开销是相当大的,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源...
  • 可以无限多个 re = 线程池3.投任务多文本参 (a, b, c, d, 到文本 (i))'.....可以无限多个 线程池1.暂停 () ' 让线程池处于工作状态线程全部暂停。 线程池1.恢复 () ' 让线程池被暂停状态线程全部恢复工作。 ...
  • public static void main(String[] args) { final ExecutorService newFixedThreadPool2 ... //多个任务 newFixedThreadPool2.execute(()->System.out.println("线程一")); newFixedThreadPool2.execute(()->S
  • spring Boot 中使用线程池异步执行多个定时任务在启动类中添加注解@EnableScheduling配置自定义线程池 在启动类中添加注解@EnableScheduling 第一步添加注解,这样才会使定时任务启动 配置自定义线程池 @...
  • 为什么要用线程池降低资源消耗。通过重复利用已创建的线程降低创建/销毁线程造成的消耗提高响应速度。当任务到达时,任务可以不需要等到线程创建就立即执行提高线程的可管理性。线程时稀缺资源,如果无限制的创建,...
  • Java线程池多线程查询数据库提高查询效率需求问题思路代码解析 需求 公司数据统计报表查询,几张大表关联查询,包含跨库查询,数据联查,数据过滤,数据统计。 问题 主表数据1 主表数据2 … 统计数据1 统计...
  • C# 线程池ThreadPool 执行多个参数方法

    千次阅读 2019-05-30 16:56:56
    ThreadPool.SetMinThreads(1, 1); ThreadPool.SetMaxThreads(10, 10); ThreadPool.QueueUserWorkItem(p={ //此次访执行代码 }); 示例: ThreadPool.QueueUserWorkItem(p => ...
  • 作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)很场景下,我们需要等待线程池的所有任务都执行完,然后再进行下一步操作。对于线程 Thread 来说,很好实现,加一 ...
  • 由于多个查询同步进行导致数据获取过慢 现使用线程池同步进行数据获取 待数据读取完毕后进行数据合并 //线程池 ExecutorService executor = Executors.newFixedThreadPool(4); List<Map<String, Object>&...
  • 加了锁和事务的方法,而且该类是针对每一商品的,即最多同时可以执行4dealOrder方法,即每商品执行该方法。 ``` @Transactional public synchronized Message dealOrder() ``` CPU核心数是固定的...
  • java中使用线程池并发执行方法

    万次阅读 2018-11-20 17:36:40
    这种做法很好,巩固知识,如果现在就像要一案例线程执行方法,大批量的原理性介绍很费时费力,甚至会导致怀疑自己的水平。 现在有业务需求是这样的:我要取story和joke两种类型里的数据。如果是串行操作就是 ...
  • 线程池的概念是什么? 在面向对象编程中,创建和销毁对象是很费时间的,...整个执行过程其实就是使用线程池中已有有限的线程把任务 队列中的任务做完。这样做的好处就是你不需要为每任务都创建一线程,因为当你创
  • 本文将介绍如何使用Java中的线程池执行任务。1 任务类型在使用线程池执行任务之前,我们弄清楚什么任务可以被线程池调用。按照任务是否有返回值可以将任务分为两种,分别是实现Runnable的任务类(无参数无返回值)和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 258,168
精华内容 103,267
关键字:

如何用线程池执行多个查询