问题总结

一、java问题汇总
  1. 线程池创建的问题

    场景:在推荐系统开发过程中,有一个数据的获取场景,模型输出的结果必须要查redis进行映射才能得到最后的结果,redis中的数据是通过hash格式存储的,每个key对固定的field的值对应了一个结果。一次post请求要查询300次redis,为了满足时延,使用多线程分3次进行查询。

    问题:创建线程池的问题,使用ThreadPoolExecutor进行线程池的创建

    使用api
    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {     this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }
        
    corePoolSize 核心线程数
    maximumPoolSize 最大线程数
    keepAliveTime 线程池中核心线程之外的其他线程空闲时存活时间
    unit 存活时间的单位
    BlockingQueue 阻塞队列
    
    忽略了两个参数
    线程工厂、线程池数达到最大和队列满的时候拒绝策略
    默认了四种拒绝策略(可以自定义拒绝策略)
    ThreadPoolExecutor.AbortPolicy() 直接抛出异常RejectedExecutionException(默认策略)
    ThreadPoolExecutor.CallerRunsPolicy() 交给主线程运行
    ThreadPoolExecutor.DiscardPolicy() 忽略后面来的任务
    ThreadPoolExecutor.DiscardOldestPolicy() 忽略队列中队首中的任务
    
    错误使用方式
    ThreadPoolExecutor(100,100,100L, TimeUnit.SECOND,new LinkedBlockingQueue<>(100))
    忽略了默认的拒绝策略,现网提交线程任务查询redis次数增加时直接报错。这种方式能提交200个任务,100个执行,100个阻塞队列中等待。
    
    修改后:
    使用Executors.newCachedThreadPool()的方式来创建线程池。默认调用的
    new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>())
    SynchronousQueue其实是不进行阻塞,直接创建新线程执行任务
    

    绘图分析线程池的线程创建流程

  2. 并发编程包中的计数器

    CountDownLatch用法

        public static void main(String[] args) {
            ArrayList<Integer> tasks = new ArrayList<>();
            CountDownLatch count = new CountDownLatch(tasks.size());
            for (Integer task : tasks) {
                pool.execute(() -> {
                    try {
                        //业务执行代码
                    } finally {
                        count.countDown();
                    }
                });
            }
            try {
                //count.await();
                boolean wait = count.await(10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
              //线程异常中断的异常
            }
        }
    }
    

    CountDownLatch先定义一个初始化的大小,每个线程执行完后减1,主线程调用await方法等待计数器减为0。如果设置了超时时间,await只等待10s,会返回一个bool值告诉主线程线程组的任务有没有执行完成。

posted on 2020-08-30 21:31  jeasonchen001  阅读(242)  评论(1编辑  收藏  举报