JAVA基础知识|Executors提供的四种线程池

时间:2021-04-14 18:33:28

一、Thread与Executors

 开启新的线程,我们经常会采用如下方法:

        Thread thread =new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("new thread");
            }
        });

通过new Thread()的方式,会导致很多弊端,如下:

  • 每一次都通过new Thread的方式,性能差。
  • 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致宕机。
  • 缺乏定时执行、定期执行、线程中断等功能。

Executors提供的四种线程池有效的解决以上问题

二、Executors提供的四种线程池

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool 创建一个定长线程池,同时支持定时及周期性任务执行。
  • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。

三、newCachedThreadPool

        ExecutorService executorService1 = Executors.newCachedThreadPool();
        Future<String> future = executorService1.submit(new Callable<String>() {

            @Override
            public String call() throws Exception {
                return "newCachedThreadPool";
            }
        });
        try {
            System.out.println(future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

四、newFixedThreadPool

        ExecutorService executorService2 = Executors.newFixedThreadPool(3);//定长3个线程
        for (int i = 0; i < 10; i++) {
            executorService2.execute(new Runnable() {//execute与submit的区别
                @Override
                public void run() {
                    try {
                        System.out.println("定长三个线程");
                        TimeUnit.SECONDS.sleep(3);//注意和Thread.sleep(3000)的区别
                    } catch (InterruptedException e) {
                        System.out.println("InterruptedException");
                    } catch (Exception e) {
                        System.out.println("Exception");
                    }
                }
            });
        }

每隔三秒钟,打印三条数据

五、newScheduledThreadPool

        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);//定长三个线程
        scheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("延迟三秒输出");
            }
        }, 3, TimeUnit.SECONDS);

延迟三秒输出

        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);//定长三个线程
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("延迟1秒,然后定期每三秒执行一次");
            }
        },1, 3, TimeUnit.SECONDS);

延迟一秒,然后定期执行

六、newSingleThreadExecutor

        ExecutorService executorService4 = Executors.newSingleThreadExecutor();
        for (int i = 1; i < 11; i++) {
            //所有被内部类访问的局部变量,都必须使用final修饰
            //对于普通局部变量而言,当方法结束以后,该局部变量也就随之消失
            //但是匿名内部类的生命周期没有结束的话,将一直可以访问局部变量的值,内部类会扩大局部变量的作用域,会引发混乱
            final int index = i;
            executorService4.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Thread:" + index);
                }
            });
        }

七、其他知识点

7.1、submit与execute的区别

  • submit支持Callable,execute支持Runable
  • submit有返回值,execute无返回值
  • submit可以捕获异常(还是因为支持Callable),execute不可以

7.2、shutdown与shutdownNow的区别

  • shutdown()方法在终止前允许执行正在进行的线程
  • shutdownNow()方法阻止新的进程并试图停止当前正在执行的线程,关闭未使用的 ExecutorService 以允许回收其资源。