第四章 线程池入门

  1. 阻塞线程的线程的特点是:该线程放弃cpu的使用,暂停运行,只有等到导致阻塞的原因消除之后才能运行。或者是被其他的线程中断,该线程也会推出阻塞状态。阻塞的原因有多种:大致分为三种来讨论,线程的阻塞,socket客户端的阻塞,socket服务器端的阻塞。
  2. 线程池的目的是提高服务器的响应能力。
4.1.1 创建线程池
public static void main(String[] args) {
        LinkedBlockingDeque<Runnable> bq = new LinkedBlockingDeque<>(5);
        ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 8, 2000, TimeUnit.MILLISECONDS, bq);
        for (int i=0;i<14;i++){
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getId()+" is running...");
                    try {
                        Thread.sleep(800);
                    }catch (Exception e){}
                }
            });
        }
        pool.shutdown();
    }
  1. 先启动核心线程,然后使用阻塞队列,最后新增线程。顺序
  2. 线程池中的线程数最大为8,当所有的任务都运行完成后,非核心线程数会在2秒后释放。

4.2 Executor接口

  1. executor接口中,只有一个executor方法,它表明在将来某个时刻,执行一个给定的任务。这个任务可以在一个新线程中或线程池中执行,也可以在调用executor方法的这个线程中执行。执行时间
  2. 执行器executor把任务的提交和任务的运行进行了有机分解,从而实现了解耦。通常无须显示创建线程。

4.3 ExecutorService接口

  1. executor接口只提供了任务的执行方法,为了解决执行服务对象的生命周期问题,executorService添加了一些用于生命周期管理的方法,如终止任务,提交任务,跟踪任务返回结果等。
  2. executorservice认为服务对象的生命周期有3种状态:运行,关闭和终止。
4.3.1 callable返回任务执行结果
static class MyTask implements Callable<String>{
        private int id;
        public MyTask(int id){
            this.id = id;
        }
        public String call() throws Exception{
            String result = "线程"+Thread.currentThread().getId()+",id="+id;
            return result;
        }
    }
    public static void main(String[] args) {
        ExecutorService pool = new ThreadPoolExecutor(3,8,2000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(5));
        List<Future<String>> results = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<String> f = pool.submit(new MyTask(i));
            results.add(f);
            System.out.println("任务:"+i+"完成");
        }
        pool.shutdown();
        for (Future<String> f : results) {
            try {
                System.out.println(f.get());
                Thread.sleep(800);
            }catch (Exception e){}
        }
    }

4.4 Executors工具箱

4.4.1 newCachedThreadPool
  1. 当需要处理大量的短时任务时,这个线程池未对任务数量做约束,而且使用synchronousQueue减少入队与出队时间,就是为了快速满足高并发请求,即大量的并发请求无须等待,即可获得服务器的线程处理。
4.4.2 newFixedThreadPool
  1. 阻塞队列非常大,Integer.MAX_VALUE,当任务数量大于核心线程数时,都会被装入队列中,充分的空间容纳待执行的任务。
4.4.3 newSingleThreadExecutor
  1. 日志服务。固定线程数为1.
  2. 好处是:业务行为与写日志完全分离开来,不会因为文件的i/o影响业务操作的并发性能。
4.4.4 newScheduledThreadPool
  1. 提供了各种延时任务和定时任务的执行,并返回可用于取消或检查执行任务的对象。
4.4.5 newWorkStealingPool
  1. 任务分解执行,然后把执行结果合并的线程池。
  2. forkjoinpool的优势在于,可以充分利用多处理器的优势,把一个任务拆分成多个比较小的任务,把这些小任务负载到多个处理器上并行执行。当这些小任务执行完成后,再将这些执行结果合并起来。

4.5 线程工厂与线程池

4.5.1线程组
4.5.2 线程与线程组
  1. 新创建的线程默认使用创建者的线程组。
4.5.5 线程池与线程工厂