一片文章看懂java自带的线程池含特性和原理

java中的两类线程池

1、ThreadPoolExecutor类线程池,下面专门用一个类来介绍

 

package com.lyzx.concurrent.threadPool;

import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * 这个类介绍和测试java自带的线程池,包括
 * 1、FixedThreadPool
 * 2、newCachedThreadPool
 * 3、SingleThreadExecutor
 * 4、ScheduledThreadPool
 */
public class PoolTest {
    private static Runnable r1= ()->{
                    for(int i=0;i<10;i++){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"::"+i);
                    }
                };

    private static Callable c1 = ()->{
        long result = 0;
        for(int i=1;i<=100;i++){
            result+= i;
        }
        return result;
    };

    /**
     * 测试FixedThreadPool和shutdown()以及isTerminated
     * newFixedThreadPool的特点有固定的大小
     * 大小不可扩展,默认的生命周期为无限即要么虚拟机关闭,要么调用shutdown()方法
     * 否则线程池一直活着
     * 使用场景:一般情况下使用线程池的首选
        其构造器如下:nThreads表示核心线程数和最大线程数一样多,也就是线程数是固定的,
        0L表示线程空闲多少时间就销毁,0表示永远不会销毁,使用LinkedBlockingQueue来持有线程,这
        种阻塞队列吞吐量比较大
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue());
    }
     */


    @Test
    public void test1(){
        Runnable[] arr = new Runnable[10];
        Arrays.fill(arr,r1);
        ExecutorService p1 = Executors.newFixedThreadPool(5);

        System.out.println("p1.isShutdown():"+p1.isShutdown()+"   p1.isTerminated():"+p1.isTerminated());
            for(Runnable r : arr){
               p1.submit(r);
            }
        p1.shutdown();
        System.out.println("p1.isShutdown():"+p1.isShutdown()+"   p1.isTerminated():"+p1.isTerminated());

        try {
            Thread.sleep(2000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("p1.isShutdown():"+p1.isShutdown()+"   p1.isTerminated():"+p1.isTerminated());
    }

    /**
     *测试newCachedThreadPool和submit()
     * newCachedThreadPool 容量无限大,只要当前的线程不能满足任务的处理
     * 就扩容,当任务执行完毕后,形成空闲时间达到60s就自动kill掉线程
     * 使用场景:在机器空闲时,处理并发高低差别很大的时候,比如并发低的时候1s不到1条请求,
     *          而并发高的时候1s有1w+的请求就适合使用这种线程池
     *
     *  Future代表未来,就是说当任务被提交(submit)后不会阻塞,而是返回一个未来对象
     *  可以通过其get()方法获取Callable的返回值,当然get()方法时阻塞的


        其构造方法如下,表示刚开始核心的线程数为0,无限创造线程,如果某个线程空闲60s就销毁,使用
        SynchronousQueue来持有Runnable任务
        public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue());
        }
     */
    @Test
    public void test2(){
        ExecutorService p1 = Executors.newCachedThreadPool();
        Callable[] arr = new Callable[5];
        Arrays.fill(arr,c1);

        List futures = new ArrayList<>();
        for(Callable c : arr){
            Future f = p1.submit(c);
            futures.add(f);
        }

        long result = 0;
        for(Future f: futures){
            try {
                Long l = f.get();
                result+=l;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        System.out.println("result::"+result);
    }

    /**
     * 测试SingleThreadExecutor 一个线程池里只有一个线程
     * 使用场景:保证任务顺序,比如多人聊天室里面的公告,发送一个公告可以由一个线程执行以确保公告
        的有序执行
        构造方法如下:
       表示只有一个线程工作,永远不会失效,使用LinkedBlockingQueue持有Runnable任务
        public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue()));
        }
     */
    @Test
    public void  test3(){
        System.out.println("=============");
        ExecutorService p1 = Executors.newSingleThreadExecutor();
        Runnable[] arr = new Runnable[10];
        Arrays.fill(arr,r1);
        for(Runnable r :arr){
            p1.execute(r);
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }

    /**
     * 测试ScheduledThreadPool,用于任务调度
     * 可以定时执行

     */
    @Test
    public void test4(){
        ScheduledExecutorService p1 = Executors.newScheduledThreadPool(5);
        //延迟2秒执行r1 只执行一次
//        p1.schedule(r1,2,TimeUnit.SECONDS);

        /**
package com.lyzx.concurrent.threadPool;

import java.util.concurrent.*;

/**
 * 分支合并线程池(mapReduce 类似的设计思想)。适合用于处理复杂任务。
 * 初始化线程容量与 CPU 核心数相关。
 * 线程池中运行的内容必须是 ForkJoinTask 的子类型(RecursiveTask,RecursiveAction)。
 * ForkJoinPool - 分支合并线程池。 可以递归完成复杂任务。 要求可分支合并的任务必须
 * 是 ForkJoinTask 类型的子类型。 其中提供了分支和合并的能力。 ForkJoinTask 类型提供了两个
 * 抽象子类型, RecursiveTask 有返回结果的分支合并任务,RecursiveAction 无返回结果的分支合并任务。(
 * Callable/Runnable) compute 方法:就是任务的执行逻辑。
 * ForkJoinPool 没有所谓的容量。默认都是 1 个线程。根据任务自动的分支新的子线程。
 * 当子线程任务结束后,自动合并。 所谓自动是根据 fork 和 join 两个方法实现的。
 * 应用: 主要是做科学计算或天文计算的。 数据分析的。
 */
public class ForkJoinPoolTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long[] arr = new long[20000];
        for(int i=0;i future = pool.submit(task);
        System.out.println(future.get());
    }
}

class JoinTask extends RecursiveTask{
    private int start,end;
    private long[] arr;
    private int target;

    public JoinTask(long[] arr,int start,int end,int target){
        this.arr = arr;
        this.start = start;
        this.end = end;
        this.target = target;
    }

    @Override
    protected Long compute() {
        /**
         * 如果分配的数组大小达到了指定的大小就执行相加的操作
         * 否则就继续拆分
         */
        if(end - start <= target){
            Long result = 0L;
            for(int i=start;i


* 按照固定的频率,没1秒钟执行一次 * 如果Runnable执行的时间 t>period,虽然是多线程但也是阻塞式的执行, * 所以尽量避免t>period的情况发生 */ p1.scheduleAtFixedRate(()->{ System.out.println(Thread.currentThread().getName()+" 开始:: "+System.currentTimeMillis()); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 结束:: "+System.currentTimeMillis()); },0,1,TimeUnit.SECONDS);// p1.shutdown(); try{ Thread.sleep(Integer.MAX_VALUE); }catch(InterruptedException e){ e.printStackTrace(); } } public static void main(String[] args){ ScheduledExecutorService p1 = Executors.newScheduledThreadPool(5); p1.scheduleAtFixedRate(r1,2000,500,TimeUnit.MILLISECONDS);// p1.shutdown(); // 定时完成任务。 scheduleAtFixedRate(Runnable, start_limit, limit, timeunit) // runnable - 要执行的任务。// p1.scheduleAtFixedRate(r1, 0, 500, TimeUnit.MILLISECONDS); }}

 

 

2、ForkJoin线程池

 

 

package com.lyzx.concurrent.threadPool;

import java.util.concurrent.*;

/**
 * 分支合并线程池(mapReduce 类似的设计思想)。适合用于处理复杂任务。
 * 初始化线程容量与 CPU 核心数相关。
 * 线程池中运行的内容必须是 ForkJoinTask 的子类型(RecursiveTask,RecursiveAction)。
 * ForkJoinPool - 分支合并线程池。 可以递归完成复杂任务。 要求可分支合并的任务必须
 * 是 ForkJoinTask 类型的子类型。 其中提供了分支和合并的能力。 ForkJoinTask 类型提供了两个
 * 抽象子类型, RecursiveTask 有返回结果的分支合并任务,RecursiveAction 无返回结果的分支合并任务。(
 * Callable/Runnable) compute 方法:就是任务的执行逻辑。
 * ForkJoinPool 没有所谓的容量。默认都是 1 个线程。根据任务自动的分支新的子线程。
 * 当子线程任务结束后,自动合并。 所谓自动是根据 fork 和 join 两个方法实现的。
 * 应用: 主要是做科学计算或天文计算的。 数据分析的。
 */
public class ForkJoinPoolTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long[] arr = new long[20000];
        for(int i=0;i future = pool.submit(task);
        System.out.println(future.get());
    }
}

class JoinTask extends RecursiveTask{
    private int start,end;
    private long[] arr;
    private int target;

    public JoinTask(long[] arr,int start,int end,int target){
        this.arr = arr;
        this.start = start;
        this.end = end;
        this.target = target;
    }

    @Override
    protected Long compute() {
        /**
         * 如果分配的数组大小达到了指定的大小就执行相加的操作
         * 否则就继续拆分
         */
        if(end - start <= target){
            Long result = 0L;
            for(int i=start;i

3、线程池的原理

 

 3.1、FixedThreadPool

 一片文章看懂java自带的线程池含特性和原理_第1张图片
 固定大小的线程池,即最核心的线程数和最大的线程数一样大,所以该不能扩容,

 另外其使用LinkedBlockingQueue ,会把大于线程数的任务放入这个阻塞队列中,等到 

 有空闲线程时从队列中取出执行

 

3.2、CachedThreadPool

 一片文章看懂java自带的线程池含特性和原理_第2张图片
  核心线程数为0,最大为“无限”,默认县城如果空闲60s就被系统回收,可以一直扩容直到系统资源耗尽或者手动关闭

 

3.3、SingleThreadExecutor

  一片文章看懂java自带的线程池含特性和原理_第3张图片

  不能扩容的线程池,是FixedThreadPool的特殊实现

 

3.4、ScheduledThreadPool

一片文章看懂java自带的线程池含特性和原理_第4张图片

 具有调度(定时)作用的线程池

 

你可能感兴趣的:(Java)