为什么要用线程池?
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制,指定队列大小,失败策略等功能,可以根据我们项目的需要自定义创建不同功能的线程池。
两种创建方式
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
示例:
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExecutorTest { 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(); } cachedThreadPool.execute(new Runnable() { public void run() { System.out.println(index); } }); } } }
说明:创建一个可缓存线程池,应用中存在的线程数可以无限大。当提交任务速度高于线程池中任务处理速度时,缓存线程池会不断的创建线程,线程数完全取决于jvm可以创建的线程数,直到资源耗尽会抛出oom异常;如果在执行第二个任务时,第一个任务已经完成,那么会复用第一个任务的线程执行第二个任务,如果一个线程超过60秒没有被使用,就会被线程池回收。所以大家要慎用此方法,适用于提交短期的异步小程序,以及负载较轻的服务器。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
示例:
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExecutorTest { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }
说明:创建一个线程数固定的线程池,可以根据系统的资源进行设置,如:Runtime.getRuntime().availableProcessors()。线程不会被回收,除非调用shutdown()方法才会回收,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。此方法可控制线程最大并发数,超出线程数据的任务会放到队列中,但是从源码中可以看到此队列为无界队列,所以如果我们一次查出的数据过多很有可能会导致oom异常,因为队列会无限扩充。使用于为了满足资源管理需求而需要限制当前线程数量的场合,使用于负载比较重的服务器但是要注意控制任务数量。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}
说明:计划型线程池,可以设置固定时间的延时或者定期执行任务,多数情况下可用来替代Timer类,同样是看线程池中有没有空闲线程,如果有,直接拿来使用,如果没有,则新建线程加入池。使用的是 DelayedWorkQueue 作为等待队列,这中类型的队列会保证只有到了指定的延时时间,才会执行任务。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())); }
说明:创建一个单线程的线程池,它只会用唯一的工作线程来执行任务,也就相当于单线程串行执行任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。使用 LinkedBlockingQueue 作为等待队列。
说明:创建一个单例线程池,定期或延时执行任务。
public static ExecutorService newWorkStealingPool(int parallelism) { return new ForkJoinPool (parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); }
说明:创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,如不穿如并行级别参数,将默认为当前系统的CPU个数。
原文:https://www.cnblogs.com/htyj/p/10849020.html