精华内容
下载资源
问答
  • 这篇文章主要介绍了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资源,应用工作窃取线程池。

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

    展开全文
  • 一个线程池执行多个任务

    千次阅读 2016-09-02 15:52:25
    今天写了些代码,测试了一下多个线程来执行多个任务的的情况,线程放在一个线程池里进行管理。 线程的数量控制在10个(当然可以指定线程池里的线程数量);任务的数量不做限制。  下面贴出代码,以备用时之需...

     今天写了些代码,测试了一下用多个线程来执行多个任务的的情况,线程放在一个线程池里进行管理。

    线程的数量控制在10个(当然可以指定线程池里的线程数量);任务的数量不做限制。

      下面贴出代码,以备用时之需。

      4个java类:1 Test.java(用于测试);2 TracingObject.java(用于传递参数的对象); 3 TracingTask.java(任务) 4 TracingThreadPool.java (管理线程的线程池)。

     

      Test:

    public class Test {

     public static void main(String[] args) {
      try {
       int poolSize = 10;
       
       //1 新增一些TracingObject
       List<TracingObject> objects = new ArrayList<TracingObject>();
       
       for(int i=1;i<=10;i++){
        objects.add(new TracingObject(new Integer(i),"file_name_" + i, "content_" + i,"description_" + i, new Integer(1)));
       }

       for(int i=1;i<=10;i++){
        objects.add(new TracingObject(new Integer(i),"maintainlog_name_" + i, "content_" + i,"description_" + i, new Integer(2)));
       }

       for(int i=1;i<=10;i++){
        objects.add(new TracingObject(new Integer(i),"db_name_" + i, "content_" + i,"description_" + i, new Integer(3)));
       }
       
       //2 创建线程池
       TracingThreadPool tracingThreadPool = new TracingThreadPool(poolSize);
       
       //3 新增一些任务到线程池中 给线程执行
       for (TracingObject tracingObject : objects) {
        tracingThreadPool.addTask(new TracingTask(tracingObject));
       }
       
       //4 等待工作线程完成所有的任务
       tracingThreadPool.join();
       
       //5 关闭线程池
       tracingThreadPool.close();
       
      } catch (Exception e) {
       // TODO: handle exception
       e.printStackTrace();
      }

     }

    }

      TracingObject:

    public class TracingObject {

        private Integer id;

        private String name;

        private String content;

        private String description;

        private Integer type;
     
     public Integer getId() {
      return id;
     }

     public void setId(Integer id) {
      this.id = id;
     }

     public String getName() {
      return name;
     }

     public void setName(String name) {
      this.name = name;
     }

     public String getContent() {
      return content;
     }

     public void setContent(String content) {
      this.content = content;
     }

     public String getDescription() {
      return description;
     }

     public void setDescription(String description) {
      this.description = description;
     }

     public Integer getType() {
      return type;
     }

     public void setType(Integer type) {
      this.type = type;
     }

     @Override
     public String toString() {
      // TODO Auto-generated method stub
      return "id:" + id
        + "\t name:" + name
        + "\t content:" + content
        + "\t description:" + description
        + "\t type:" + type;
     }

     public TracingObject(Integer id, String name, String content,
       String description, Integer type) {
      super();
      this.id = id;
      this.name = name;
      this.content = content;
      this.description = description;
      this.type = type;
     }

    }

      TracingTask:

    public class TracingTask implements Runnable {

     private TracingObject tracingObject;
     
     private TracingTask() {}

     public TracingTask(TracingObject tracingObject) {
      this.tracingObject = tracingObject;
     }

     
     public void run() {
      // TODO Auto-generated method stub
      try {
       System.out.println(Thread.currentThread().getName() + "\t" + this.tracingObject);
       // 增加执行一个任务的时间,3秒
       Thread.sleep(3000);
      } catch (InterruptedException ex) {
      }
     }
    }

      TracingThreadPool:

    public class TracingThreadPool extends ThreadGroup {
     // 线程池是否关闭
     private boolean isClosed = false;
     // 表示工作队列
     private LinkedList<Runnable> workQueue;
     // 表示线程池ID
     private static int threadPoolID;
     // 表示工作线程ID
     private int threadID;

      // poolSize指定线程池中的工作线程数目
     public TracingThreadPool(int poolSize) {
      super("ThreadPool-" + (threadPoolID++));
      setDaemon(true);
      // 创建工作队列
      workQueue = new LinkedList<Runnable>();
      // 打印起始时间
      System.out.println("start time:" + (new Date()));

      for (int i = 0; i < poolSize; i++)
       // 创建并启动工作线程
       new WorkThread().start();
     }

     
     public synchronized void addTask(Runnable task) {
      // 线程池被关则抛出IllegalStateException异常
      if (isClosed) {
       throw new IllegalStateException();
      }
      if (task != null) {
       workQueue.add(task);
       // 唤醒正在getTask()方法中等待任务的工作线程
       notify();
      }
     }

     
     protected synchronized Runnable getTask() throws InterruptedException {
      while (workQueue.size() == 0) {
       if (isClosed)
        return null;
       // 如果工作队列中没有任务,就等待任务
       wait();
      }
      return workQueue.removeFirst();
     }

     
     public synchronized void close() {
      if (!isClosed) {
       isClosed = true;
       workQueue.clear(); // 清空工作队列
       interrupt(); // 中断所有的工作线程,该方法继承自ThreadGroup类
      }
     }

     
     public void join() {
      synchronized (this) {
       isClosed = true;
       // 唤醒还在getTask()方法中等待任务的工作线程
       notifyAll();
      }

      Thread[] threads = new Thread[activeCount()];
      //获得线程组中当前所有活着的工作线程
      int count = enumerate(threads);
      // 等待所有工作线程运行结束
      for (int i = 0; i < count; i++) {
       try {
        // 等待工作线程运行结束
        threads[i].join();
       } catch (InterruptedException ex) {
       }
      }
      //打印结束时间
      System.out.println("end time:" + (new Date()));
     }

     
     private class WorkThread extends Thread {
      public WorkThread() {
       // 加入到当前ThreadPool线程组中
       super(TracingThreadPool.this, "WorkThread-" + (threadID++));
      }

      public void run() {
       while (!isInterrupted()) { // isInterrupted()方法继承自Thread类,判断线程是否被中断
        Runnable task = null;
        try {
         // 得到任务
         task = getTask();
        } catch (InterruptedException ex) {
        }

        // 如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程
        if (task == null)
         return;

        try {
         // 运行任务,捕获异常
         task.run();
        } catch (Throwable t) {
         t.printStackTrace();
        }
       }
      }
     }
    }

    展开全文
  • 使用线程池执行多线程需要如下几条件 首先是一线程池,线程池包含一些初始化数据,包含队列大小,核心线程数,最大线程数。 然后是一实现了 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 框架提供了一些基础的组件能够轻松的完成...

    Java在语言层面提供了多线程的支持,线程池能够避免频繁的线程创建和销毁的开销,因此很多时候在项目当中我们是使用的线程池去完成多线程的任务。
    Java提供了Executors 框架提供了一些基础的组件能够轻松的完成多线程异步的操作,Executors提供了一系列的静态工厂方法能够获取不同的ExecutorService实现,ExecutorService扩展了Executors接口,Executors相当简单:

    public interface Executor {
        void execute(Runnable command);
    }
    
    

    把任务本身和任务的执行解耦了,如果说Runnable是可异步执行任务的抽象,那Executor就是如何执行可异步执行任务的抽象,说起来比较绕口。
    本文不讲解线程的一些基础知识,因为网上的其他文章已经写的足够详细和泛滥。我写写多个异步任务的并发执行与结果的获取问题。假设这样一个场景:我们要组装一个对象,这个对象由大量小的内容组成,这些内容是无关联无依赖关系的,如果我们串行的去执行,如果每个任务耗时10秒钟,一共有10个任务,那我们就需要100秒才能获取到结果。显然我们可以采用线程池,每个任务起一个线程,忽略线程启动时间,我们只需要10秒钟就能获取到结果。这里还有两种选择,这10秒钟我们可以去做其他事,也可以等待结果。
    我们来完成这样的操作:

    // 这是任务的抽象
    class GetContentTask implements Callable<String> {
    		
    		private String name;
    		
    		private Integer sleepTimes;
    		
    		public GetContentTask(String name, Integer sleepTimes) {
    			this.name = name;
    			this.sleepTimes = sleepTimes;
    		}
    		public String call() throws Exception {
    			// 假设这是一个比较耗时的操作
    			Thread.sleep(sleepTimes * 1000);
    			return "this is content : hello " + this.name;
    		}
    		
    	}
    

    采用completionService :

    // 方法一
    		ExecutorService executorService = Executors.newCachedThreadPool();
    		CompletionService<String> completionService = new ExecutorCompletionService(executorService);
    		ExecuteServiceDemo executeServiceDemo = new ExecuteServiceDemo();
    		// 十个
    		long startTime = System.currentTimeMillis();
    		int count = 0;
    		for (int i = 0;i < 10;i ++) {
    			count ++;
    			GetContentTask getContentTask = new ExecuteServiceDemo.GetContentTask("micro" + i, 10);
    			completionService.submit(getContentTask);
    		}
    		System.out.println("提交完任务,主线程空闲了, 可以去做一些事情。");
    		// 假装做了8秒种其他事情
    		try {
    			Thread.sleep(8000);
    			System.out.println("主线程做完了,等待结果");
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		try {
    			// 做完事情要结果
    			for (int i = 0;i < count;i ++) {
    				Future<String> result = completionService.take();
    				System.out.println(result.get());
    			}
    			long endTime = System.currentTimeMillis();
    			System.out.println("耗时 : " + (endTime - startTime) / 1000);
    		}  catch (Exception ex) {
    			System.out.println(ex.getMessage());
    		}
    

    执行结果为:

    提交完任务,主线程空闲了, 可以去做一些事情。
    主线程做完了,等待结果
    this is content : hello micro9
    this is content : hello micro7
    this is content : hello micro2
    this is content : hello micro5
    this is content : hello micro4
    this is content : hello micro8
    this is content : hello micro1
    this is content : hello micro3
    this is content : hello micro0
    this is content : hello micro6
    耗时 : 10
    

    如果多个不想一个一个提交,可以采用 invokeAll一并提交,但是会同步等待这些任务

    // 方法二
    		ExecutorService executeService = Executors.newCachedThreadPool();
    		List<GetContentTask> taskList = new ArrayList<GetContentTask>();
    		long startTime = System.currentTimeMillis();
    		for (int i = 0;i < 10;i ++) {
    			taskList.add(new GetContentTask("micro" + i, 10));
    		}
    		try {
    			System.out.println("主线程发起异步任务请求");
    			List<Future<String>> resultList = executeService.invokeAll(taskList);
    			// 这里会阻塞等待resultList获取到所有异步执行的结果才会执行 
    			for (Future<String> future : resultList) {
    				System.out.println(future.get());
    			}
    			// 主线程假装很忙执行8秒钟
    			Thread.sleep(8);
    			long endTime = System.currentTimeMillis();
    			System.out.println("耗时 : " + (endTime - startTime) / 1000);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
    主线程发起异步任务请求
    this is content : hello micro0
    this is content : hello micro1
    this is content : hello micro2
    this is content : hello micro3
    this is content : hello micro4
    this is content : hello micro5
    this is content : hello micro6
    this is content : hello micro7
    this is content : hello micro8
    this is content : hello micro9
    耗时 : 10
    

    如果一系列请求,我们并不需要等待每个请求,我们可以invokeAny,只要某一个请求返回即可。

    ExecutorService executorService = Executors.newCachedThreadPool();
    		ArrayList<GetContentTask> taskList = new ArrayList<GetContentTask>();
    		taskList.add(new GetContentTask("micro1",3));
    		taskList.add(new GetContentTask("micro2", 6));
    		try {
    			List<Future<String>> resultList = executorService.invokeAll(taskList);// 等待6秒 
    //			String result2 = executorService.invokeAny(taskList); // 等待3秒
    			// invokeAll 提交一堆任务并行处理并拿到结果
    			// invokeAny就是提交一堆并行任务拿到一个结果即可
    			for (Future<String> result : resultList) {
    				System.out.println(result.get());
    			}
    //			System.out.println(result2);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		System.out.println("主线程等待");
    

    如果我虽然发送了一堆异步的任务,但是我只等待一定的时间,在规定的时间没有返回我就不要了,例如很多时候的网络请求其他服务器如果要数据,由于网络原因不能一直等待,在规定时间内去拿,拿不到就我使用一个默认值。这样的场景,我们可以使用下面的写法:

    try {
    			ExecutorService executorService = Executors.newCachedThreadPool();
    			List<Callable<String>> taskList = new ArrayList<Callable<String>>();
    			taskList.add(new GetContentTask("micro1", 4));
    			taskList.add(new GetContentTask("micro2", 6));
    			// 等待五秒
    			List<Future<String>> resultList = executorService.invokeAll(taskList, 5, TimeUnit.SECONDS);
    			for (Future<String> future : resultList) {
    				System.out.println(future.get());
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} 
    
    this is content : hello micro1
    java.util.concurrent.CancellationException
    	at java.util.concurrent.FutureTask.report(FutureTask.java:121)
    	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    	at com.micro.demo.spring.ExecuteServiceDemo.main(ExecuteServiceDemo.java:105)
    

    因为只等待5秒,6秒的那个任务自然获取不到,抛出异常,如果将等待时间设置成8秒,就都能获取到。

    展开全文
  • spring Boot 中使用线程池异步执行多个定时任务在启动类中添加注解@EnableScheduling配置自定义线程池 在启动类中添加注解@EnableScheduling 第一步添加注解,这样才会使定时任务启动 配置自定义线程池 @...
  • 多线程-线程池执行多业务逻辑

    千次阅读 2019-04-18 15:43:27
    线程池执行不同的业务逻辑. * 2.获取每任务执行的结果 * 3.最后的结果会用到之前的结果 */ public class SearchUserListDTO { public static void main(String[] args) throws InterruptedException { ...
  • 代码如下 : ... import java.util.HashSet; import java.util.List;...import java.util.Set;...import java.util.concurrent.*;...执行结果如下 : future task: task2 future task: task1 future task: task3
  • C# 线程池ThreadPool 执行多个参数方法

    千次阅读 2019-05-30 16:56:56
    ThreadPool.SetMinThreads(1, 1); ThreadPool.SetMaxThreads(10, 10); ThreadPool.QueueUserWorkItem(p={ //此次访执行代码 }); 示例: ThreadPool.QueueUserWorkItem(p => ...
  • 线程池执行顺序

    千次阅读 2019-12-11 09:39:08
    线程池提交任务时,会首先判断线程池中的线程数是否大于设置的核心线程数,如果不大于,就创建一核心线程来执行任务。 如果大于核心线程数,就会判断缓冲队列是否满了,如果没有满,则放入队列,等待线程空闲时...
  • 加了锁和事务的方法,而且该类是针对每一商品的,即最多同时可以执行4dealOrder方法,即每商品执行该方法。 ``` @Transactional public synchronized Message dealOrder() ``` CPU核心数是固定的...
  • 记录 Spring 项目中的线程池执行线程任务(多少时间之后执行)
  • 使用线程池时,几注意点: 1、设置独立的线程名规则,区分自动生成的线程名; 2、直接使用ThreadPoolExecutor,而不是借用Executors类生成; 3、利用Future的阻塞特性来控制全部线程执行结束的时间点。 代码参考...
  • 开启线程 public class MultithreadScheduleTask { @Async @Scheduled(fixedDelay = 1000) //间隔1秒 public void first() throws InterruptedException { System.out.println("第一定时任务开始 : " + ...
  • 我是使用的java线程池ThreadPoolExecutor,实现分批次去查询查询到数据后,又分多个线程去做业务。 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:ThreadPoolExecutor(int corePoolSize,...
  • 在现实世界里,我们总是免不了要定期去做一件事情(比如上课)—— 在计算机的世界里,更是如此。...在 使用线程池 中已经介绍,JDK 1.5 时,标准类库添加了对线程池的支持,然后在线程池核心实现 ThreadP...
  • public static void main(String[] args) throws ExecutionException, InterruptedException { ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,...//等线程执行完返回数据 System.out.println(s); }
  • 应用部署在了四台服务器上,如何在竞争到锁的服务器上处理订单生成订单流水的速度更快,考虑使用个线程池去负责读取数据,一个线程池负责去插入数据,在此之前先编写一Demo类来测试方案是否可行。 一、首先回顾...
  • 线程池是为了控制一个进程中线程过多而导致内存溢出的问题,队列主要是为了解决了某一时刻请求过多而出现的宕机情况,同时能接收处理更多的请求,可以将多个请求放置到队列中,等待线程依次执行,而客户端则可以...
  • 线程池运行多个线程

    千次阅读 2019-06-05 15:06:23
    ToastUtils.showToast(context, "已导入" + contactList.size() + "联系人"); Intent intent = new Intent(); intent.setAction("com.newingscom.iwcontact.main.update"); context.sendBroadcast(intent); ...
  • 写一个程序,在线程池中提交多个任务,每个任务最终都有一个执行结果,需求是对每个任务的执行结果进行汇总(样例中是把结果加在一起)。这里使用线程池的submit方法和Future实现。 定义一个任务类 import java....
  • 线程池 spring内置了ThreadPoolTaskExecutor线程池,可以直接初始化后声明为bean,在上下文的任意位置进行依赖注入。 线程实例的方法 如果你的线程不需要返回值,可以调用ThreadPoolTaskExecutor bean实例的execute...
  • 定时线程池执行任务时任务执行时间与定时关系 1、当执行时间小于定时时间的时候 System.out.println("执行的时间小于设定的周期"); ScheduledExecutorService service = Executors.newScheduledThreadPool(1); ...
  • 并发编程经历:线程池使用

    万次阅读 多人点赞 2019-07-31 18:38:24
    使用线程池管理线程可以最大程度的利用线程,节省资源消耗,它通过利用已有的线程多次循环执行多个任务从而提高系统的处理能力。 我们可以通过java.util.concurrent.ThreadPoolExecutor类来创建线程池,一个任务通过...
  • Java 判断线程池 执行完毕

    千次阅读 2014-04-14 20:10:36
    工作中,遇到很情况需要使用线程,或者线程池。但往往我们需要dengda
  • 其实线程处理的方式有很线程池,自定义线程等等,但是需要同时执行,所以这里线程池和CountDownLatch这类来进行处理 其实思路很简单,首先通过线程池划分好线程明细,然后通过线程池的submit进行处理,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 221,462
精华内容 88,584
关键字:

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