一、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 以允许回收其资源。