8.线程池

自定义线程池:

/**
 * 自定义线程池
 */
public class UserThreadFactory implements ThreadFactory {

    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    public UserThreadFactory(String whatFeatOfGroup) {
        namePrefix = "From UserThreadFactory's "+whatFeatOfGroup+" Worker!";//线程名字
    }

    @Override
    public Thread newThread(Runnable task) {
        String name = namePrefix+nextId.getAndIncrement();//线程名字+CAS
        Thread thread = new Thread(null,task,name,0);
        System.out.println(thread.getName());
        return thread;
    }
}

线程池:

线程池
  • 目前JDK自带两种:

    1.ThreadPoolExecutor:普通的(背过)
    多个线程维护一个队列;
    1.corePoolSize,核心线程;
    2.maximumPoolSize,最大线程;
    3.keepAliveTime,生存时间,很长时间不干活了,归还操作系统;
    4.TimeUnit,生存时间单位,毫秒,纳秒,秒可以自己定义;
    5.BlockingQueue,任务队列,各种Queue都可以往进放;
    6.ThreadFactory,线程工厂,产生线程的;
    1.指定了group,制定了线程的名字;
    2.绝对不是守护线程;
    7.RejectedExecutionHandler,拒绝策略,线程池忙,队列满,可以拒绝,拒绝策略可以自定义,JDK提供了四种:
    1.Abort;抛异常
    2.Discard; 扔掉,不抛异常
    3.DiscardOldest;扔掉排队时间最久的
    4.CallerRuns;谁提交,谁调用,调用者处理任务

    2.ForkJoinPool:Fork分叉,最后结果汇总join
    每个线程都有自己的队列

ThreadPoolExecutor源码解析
  • 常用变量的解释
  • 构造方法
  • 提交执行task的过程
  • addWorker源码解析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9GKE6AHH-1627494216522)(http://note.youdao.com/yws/res/7401/WEBRESOURCE607d3046ead2c6c97e3579870b862354)]

底层都是ThreadPool线程池

ThreadPoolExecutor
  • SingleThreadPool 一个线程的线程池
    1.只有一个线程;
    Q:为什么要有单线程的线程池?
    A:1.线程池是由任务队列的;
      2.生命周期管理;
ExecutorService executorService = Executors.newSingleThreadExecutor();
//源码
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  • CachedThreadPool 弹性的线程池,来一个启动一个
 ExecutorService executorService1 = Executors.newCachedThreadPool();
 //源码
     public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    //没有核心线程数
    //SynchronousQueue
    //来一个新的任务必须马上执行,没有线程空的就立马new一个新的线程
  • FixedThreadPool 并行执行,固定多少个线程的线程池
    ExecutorService executorService2 = Executors.newFixedThreadPool(5);
    //源码
        public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    //是没有最大线程数的,核心线程数=最大线程数,所以不需要回收
Q:什么时候用CachedThreadPool,什么时候用FixedThreadPool?
A:任务忽高忽低,用CachedThreadPool;平稳用FixedThreadPool;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sPxk2ode-1627494216523)(http://note.youdao.com/yws/res/7375/WEBRESOURCE304ff712ec2778662084594db00b8449)]

  • ScheduledThreadPool 定时任务线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
//源码
   public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    
DelayedWorkQueue 指定隔多长时间之后开始执行;
用的也不多,复杂的话就直接用定时任务框架 qyartz  cron;

面试题:一个闹钟服务,订阅这个服务的很多,10E人,怎么优化?
分而治之,主服务器把请求转发不同的边缘服务,用队列存储,线程池消化;
并行和并发的区别
并发:任务提交
并行:任务执行
并行是并发的子集;
ForkJoinPool
  • WorkStealingPool

    原理:
    1.多个work Queue,每一个线程维护一个一个队列
    2.采用work stealing算法

    里边就是new了一个ForkJoinPool

ExecutorService executorService3 = Executors.newWorkStealingPool();
源码:
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
  • ForkJoinPool

    原理:
    1.将一个大任务切换成一个个小任务;
    2.将结果在进行汇总;

    代码:
    1.创建一个ForkJoinPool对象,初始化线程个数
    ForkJoinPool pool = new ForkJoinPool(3);
    2.调用pool的invork()方法,传入一个ForkJoinTask调度器,ForkJoinTask代表一个可并行合并的任务;
    3.ForkJoinTask有两个抽象子类,
    RecursiveTask:代表有返回值的任务
    RecursiveAction:代表无返回值的任务
    4.重写RecursiveTask类中的compure方法,可以实现任务分叉,
    比如:RecursiveTask1任务与RecursiveTask2任务
    分叉:
    RecursiveTask1.fork();
    RecursiveTask2.fork();
    合并:
    int a = RecursiveTask1.join();
    int b = RecursiveTask2.join();
    返回:
    return a+b;

没有返回值的继承 RecursiveAction
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cGKEqgvq-1627494216524)(http://note.youdao.com/yws/res/7424/WEBRESOURCE1871ec8a1bd77d829d4b03aa45c7b277)]

有返回值的继承 RecursiveTask<返回值>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值