常見問題之線程池

  • 爲什麼要用線程池
    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,功能完善

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章