常见问题之线程池

  • 为什么要用线程池
    1.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗
    2.提高响应速度:任务到达时不需要等待线程创建就可以立即执行
    3.提高线程的可管理性:线程池可以统一管理、分配、调优和监控

  • 线程的四种创建方式
    1.Executors.newFixedThreadPool 创建一个coreSize=maxSize=n的线程池,每个线程不限制空闲时间,一直阻塞等待任务(LinkedBlockingQueue)
    2. Executors.newCachedThreadPool 创建一个coreSize=0, maxSize=Integer.MAX_VALUE, 每个线程最大空闲时间不能超过60s,否则强制退出(SynchronousQueue)
    3. Executors.newSingleThreadExecutor 创建一个coreSize=maxSize=1的线程池,每个线程不限制空闲时间,一直阻塞等待任务,不存在并发,保证任务有序执行完(LinkedBlockingQueue)
    4. Executors.newScheduledThreadPool 创建一个coreSize=0, maxSize=Integer.MAX_VALUE,每个线程空闲时间设置0,否则强制退出(DelayedWorkQueue)

  • 线程池的重要参数
    1.allowCoreThreadTimeOut 指定核心线程是否允许超时,非核心线程写死在代码里面一定是有空闲时间限制的

    boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
    

    2 .keepAliveTime 指定核心线程或者非核心线程的最大空闲时间
    3.corePoolSize 指定核心线程数量
    4.maximumPoolSize 指定最大线程数量
    5.RejectedExecutionHandler 指定使用的拒绝策略(AbortPolicy,DiscardPolicy,DiscardOldestPolicy,CallerRunsPolicy)
    6.ThreadFactory 指定创建线程的工厂实现

  • 线程池应用----多个任务都完成做统计

    //用栅栏
    public class Test5 {
          
          
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
          
          
    
            CountDownLatch countDownLatch = new CountDownLatch(5);
    
            List<FutureTask> futureTaskList=new ArrayList<>();
    
            for(int i=1;i<=100;i++) {
          
          
                FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new Task(i,countDownLatch));
                futureTaskList.add(integerFutureTask);
                new Thread(integerFutureTask).start();
            }
    
            countDownLatch.await();
    
            int count=0;
    
            for (FutureTask<Integer> futureTask: futureTaskList
                 ) {
          
          
                count+=futureTask.get();
            }
    
            System.out.println("统计:"+count);
        }
    
    }
    
    class Task implements Callable<Integer> {
          
          
    
        private Integer integer;
    
        private CountDownLatch countDownLatch;
    
        public Task(Integer integer) {
          
          
            this.integer = integer;
        }
    
        public Task(Integer integer, CountDownLatch countDownLatch) {
          
          
            this.integer = integer;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public Integer call() throws Exception {
          
          
            countDownLatch.countDown();
            return integer;
        }
    }
    
  • 线程池应用—百万任务如何快速处理

    /**
     * 假设一个任务消耗2毫秒,那么单线程处理10万个任务需要200秒
     * 使用forkjoin,会将大任务拆成小任务,拆分的每个小任务会有一个线程处理,相当于多个线程同时处理
     */
    public class ForkJoinTask {
          
          
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
          
          
    
    
            System.out.println("开始时间:"+new Date());
            ForkJoinPool forkJoinPool = new ForkJoinPool();
    
            Long integer = forkJoinPool.submit(new Task(1L, 100000L)).get();
    
            System.out.println("计算结果:"+integer);
            System.out.println("开始时间:"+new Date());
    
            System.out.println("开始时间2:"+new Date());
            Long sum=0L;
            Long i=1L;
            while (i<=100000L){
          
          
                sum+=i;
                i++;
                Thread.sleep(2);
            }
            System.out.println(sum);
            System.out.println("开始时间2:"+new Date());
        }
    
    }
    
    
    class Task extends RecursiveTask<Long>{
          
          
    
        private Long start;
    
        private Long end;
    
        public Task(Long start, Long end) {
          
          
            this.start = start;
            this.end = end;
        }
    
        @Override
        protected Long compute() {
          
          
    
            Long sum=0L;
    
            boolean canCompute=(end-start)<=2;
    
            if(canCompute){
          
          
    
                for(Long i=start;i<=end;i++){
          
          
                    sum+=i;
                    try {
          
          
                        Thread.sleep(2);
                    } catch (InterruptedException e) {
          
          
                        e.printStackTrace();
                    }
                }
    
            }else {
          
          
    
                Long middle=(start+end)/2;
    
                Task task = new Task(start, middle);
    
                Task task1 = new Task(middle + 1, end);
    
                task.fork();
                task1.fork();
    
                Long join = task.join();
                Long join1 = task1.join();
    
                sum=join+join1;
    
            }
    
            return sum;
        }
    }
    
    开始时间:Fri Apr 24 22:28:16 CST 2020
    计算结果:5000050000
    开始时间:Fri Apr 24 22:28:38 CST 2020
    开始时间2:Fri Apr 24 22:28:38 CST 2020
    5000050000
    开始时间2:Fri Apr 24 22:32:47 CST 2020
    
  • CountDownLatch和ForkJoinTask对比
    1.都可以通过阻塞,等到所有任务执行完再统计结果
    2.CountDownLatch没有任务切分功能,ForkJoinTask可以有任务切分功能
    3.CountDownLatch线程开销大,ForkJoinTask一个线程可以处理一批任务
    4.大部分还是使用ForkJoinTask,功能完善

猜你喜欢

转载自blog.csdn.net/weixin_38312719/article/details/105512982