一片文章看懂java提供的线程池

1、java线程池最顶级的接口Executor


  只有一个execute方法,这个方法时用来执行Runnable类型的command实例的

2、Executor接口的子接口ExecutorService


可以看到里面提供的方法

submit()      :提交一个"任务",既可以是Runnable也可以是Callable

shutdown() :优雅的关闭一个线程池,如果关闭时线程池中还有执行的任务,则不再接受新的任务,并把没有执行完毕的任务全部执行完毕后再关闭,并回收所有线程。

shutdownNow(): 粗暴地关闭线程池,不管是不是还有任务正在执行,并回收所有线程。

isShutdown()    是不是已经关闭了,只要调用了shutdown()就返回true

isTerminated()  是不是彻底关闭了


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.*;


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<Long> c1 = ()->{
        long result = 0;
        for(int i=1;i<=100;i++){
            result+= i;
        }
        return result;
    };


    /**
     * 测试FixedThreadPool和shutdown()以及isTerminated
     * newFixedThreadPool的特点有固定的大小
     * 大小不可扩展,默认的生命周期为无限即要么虚拟机关闭,要么调用shutdown()方法
     * 否则线程池一直活着
     * 使用场景:一般情况下使用线程池的首选
     */
    @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()方法时阻塞的
     */
    @Test
    public void test2(){
        ExecutorService p1 = Executors.newCachedThreadPool();
        Callable<Long>[] arr = new Callable[5];
        Arrays.fill(arr,c1);


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


        long result = 0;
        for(Future<Long> 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 一个线程池里只有一个线程
     * 使用场景:保证任务顺序,比如多人聊天室里面的公告,发送一个公告可以由一个线程执行以确保公告的有序执行
     */
    @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);


        /**
         * 按照固定的频率,没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);
        
    }

}








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<arr.length;i++){
            arr[i]=i;
        }


        ForkJoinPool pool = new ForkJoinPool();
        JoinTask task = new JoinTask(arr,0,arr.length,50);
        Future<Long> future = pool.submit(task);
        System.out.println(future.get());
    }
}


class JoinTask extends RecursiveTask<Long>{
    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<end;i++){
                result+= arr[i];
            }
            return  result;
        }else{
            int mid = start + (end - start)/2;
            JoinTask j1 = new JoinTask(arr,start,mid,target);
            JoinTask j2 = new JoinTask(arr,mid,end,target);
            //fork()方法时继续查分即会继续调用compute方法
            j1.fork();
            j2.fork();
            return j1.join()+j2.join();
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值