转载:https://blog.csdn.net/tanghui270270/article/details/80595961
1.new Thread的弊端
执行一个异步任务你还只是如下new Thread吗?
new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start();
1-1 说说弊端:
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
1-2 相比new Thread,Java提供的四种线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。
2.Executors提供四种线程池
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程池的规模不存在限制。
newFixedThreadPool 创建一个固定长度线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个固定长度线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
将线程放入线程池的两种方法
1- ExecutorService 类中的 submit(Runnable task) submit(Callable<T> task)
2- Executor 接口中的execute(Runnable command)
3.实例
3-1 newCachedThreadPool
package com.th.threadPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2018/6/6. * newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程, * 若无可回收,则新建线程。线程池的规模不存在限制。 */ public class NewCachedThreadPool { public static void main(String[] args) { ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } //1- 在未来某个时间执行给定的命令。 // 该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。 cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(index); } }); //2- 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 // 该 Future 的 get 方法在成功完成时将会返回给定的结果 cachedThreadPool.submit(new Runnable() { @Override public void run() { System.out.println(index); } }); } cachedThreadPool.shutdown(); } }
3-2 newFixedThreadPool
package com.th.threadPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2018/6/6. * * newFixedThreadPool 创建一个固定长度线程池,可控制线程最大并发数,超出的线程会在队列中等待。 */ public class NewFixedThreadPool { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); for (int i = 0; i < 10; i++) { final int index = i; //1- 在未来某个时间执行给定的命令。 // 该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。 fixedThreadPool.execute(new Runnable() { @Override public void run() { threadRunMethod(index); } }); //2- 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 // 该 Future 的 get 方法在成功完成时将会返回给定的结果 fixedThreadPool.submit(new Runnable() { @Override public void run() { threadRunMethod(index); } }); } fixedThreadPool.shutdown(); } /** * * @param index */ private static void threadRunMethod(int index) { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
3-3 newScheduledThreadPool
package com.th.threadPool; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * Created by Administrator on 2018/6/6. * newScheduledThreadPool 创建一个固定长度线程池,支持定时及周期性任务执行。 */ public class NewScheduledThreadPool { public static void main(String[] args) { ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); //testSchedule(scheduledExecutorService); //testScheduleAtFixedRate(scheduledExecutorService); testScheduleWithFixedDelay(scheduledExecutorService); // 终止线程池 //scheduledExecutorService.shutdown(); } /** * * 跟 testScheduleAtFixedRate 非常类似,就是延迟的时间有点区别 * 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期; * 也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行, * 接着在 initialDelay + 2 * period 后执行,依此类推。 * * 如果任务里面执行的时间大于 period 的时间,下一次的任务会推迟执行。 * 推迟的时间 : 等到上次的任务执行完之后再延迟period 的时间后执行。 * @param scheduledExecutorService */ private static void testScheduleWithFixedDelay(ScheduledExecutorService scheduledExecutorService) { scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { try { System.out.println("延迟2秒,再3秒执行一次"); //如果任务里面执行的时间大于 period 的时间,下一次的任务会推迟执行。 //本次任务执行完后下次的任务还需要延迟period时间后再执行 Thread.sleep(6*1000); } catch (InterruptedException e) { e.printStackTrace(); } } },2,3,TimeUnit.SECONDS); } /** * 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期; * 也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行, * 接着在 initialDelay + 2 * period 后执行,依此类推。 * * 如果任务里面执行的时间大于 period 的时间,下一次的任务会推迟执行。 * 推迟的时间 : 等到上次的任务执行完就立马执行。 * @param scheduledExecutorService */ private static void testScheduleAtFixedRate(ScheduledExecutorService scheduledExecutorService) { scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { System.out.println("延迟2秒,再3秒执行一次"); //如果任务里面执行的时间大于 period 的时间,下一次的任务会推迟执行。 //如果任务里面执行的时间大于 period 的时间,本次任务执行完后,下次任务立马执行。 Thread.sleep(6*1000); } catch (InterruptedException e) { e.printStackTrace(); } } },2,3,TimeUnit.SECONDS); } /** * 创建并执行在给定延迟后启用的一次性操作 * @param scheduledExecutorService */ private static void testSchedule(ScheduledExecutorService scheduledExecutorService) { scheduledExecutorService.schedule(new Runnable() { @Override public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS); } }
3-4 newSingleThreadExecutor
package com.th.threadPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by Administrator on 2018/6/6. * newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务, * 保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。 */ public class NewSingleThreadExecutor { public static void main(String[] args) { ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; /*singleThreadExecutor.execute(new Runnable() { @Override public void run() { try { System.out.println("newSingleThreadExecutor: " + index); Thread.sleep(2*1000); } catch (Exception e) { e.printStackTrace(); } } });*/ singleThreadExecutor.submit(new Runnable() { @Override public void run() { try { System.out.println("newSingleThreadExecutor: " + index); Thread.sleep(2*1000); } catch (Exception e) { e.printStackTrace(); } } }); } singleThreadExecutor.shutdown(); } }