线程池java实现,java常用的线程池如何选择
00-1010线程池的好处创建线程池的五种方法cache dthreadpool fixed threadpool SingleThreadExecutor调度任务线程池Scheduled threadpoolthhreadpoolexecutor创建线程池(强烈推荐)eadpoolexecutor的Thr七个参数详细解释了workQueuehandler如何触发拒绝策略和线程池扩展。
00-1010可以实现线程的重用,避免了线程的重新创建和销毁。创建和销毁线程会耗费大量CPU资源。您可以限制可以创建的最大线程数,并根据您自己的机器性能动态调整线程池参数,以提高应用程序性能。提供定时执行、并发控制等功能。统一管理线程。
00-1010 1:缓存线程池(不推荐)
2:固定容量线程池(不推荐)
3:单线程池(不推荐)
4:定时任务线程池(不推荐)
5.通过ThreadPoolExecutor构造方法创建线程池(阿里巴巴的开发手册强烈推荐)
创建线程池的前四种方法都是由执行器的静态方法创建的。
目录
ExecutorService ExecutorService=executors . newcachedthreadpool();for(int I=0;i 10I){ final int finalI=I;executorservice . execute(new Runnable(){ public void run(){ system . out . println(thread . current thread()。getName() thread-run finalI);} });}为什么不建议使用缓存线程池?
源代码分析
public static ExecutorService newCachedThreadPool(){ return new threadpool executor(0,2147483647,60L,TimeUnit。秒,new synchronous queue());} public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit Unit,BlockingQueueRunnable workQueue){ this(corePoolSize,maximumPoolSize,keepAliveTime,unit,work queue,Executors.defaultThreadFactory(),default handler);}通过上面两段代码我们可以看到,CachedThreadPool的maximumPoolSize是整数2147483647的最大值,相当于无限期地创建线程,而创建线程需要内存,会造成内存溢出。而且普通机器也不会用那么多内存给它创建那么多线程。
00-1010 newfixedthreadpool(int num),num是我们要指定的线程的固定数量。
ExecutorService ExecutorService=executors . newfixedthreadpool(5);for(int I=0;i 10I){ final int finalI=I;executorservice . execute(new Runnable(){ public void run(){ system . out . println(thread . current thread()。getName() thread-run finalI);} });}输出:
线程池1线程5线程g
t;run>4pool-1-thread-4<thread->run>3pool-1-thread-5<thread->run>5pool-1-thread-3<thread->run>2pool-1-thread-3<thread->run>8pool-1-thread-3<thread->run>9pool-1-thread-2<thread->run>1pool-1-thread-1<thread->run>0pool-1-thread-5<thread->run>7pool-1-thread-4<thread->run>6
可以看出起到了线程的复用。
为什么FixedThreadPool是固定线程池?
源码分析
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
通过这个源码可以看出,核心线程数(corePoolSize)和最大线程数(maximumPoolSize)都为nThreads,因为只有这样,线程池才不会进行扩容,线程数才固定。
单个线程池SingleThreadExecutor
ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
为什么SingleThreadExecutor只含有一个线程?
源码分析
public static ExecutorService newSingleThreadExecutor() { return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }
通过这个源码可以看出,核心线程数(corePoolSize)和最大线程数(maximumPoolSize)都为1,所以它只含有一个线程。
定时任务线程池ScheduledThreadPool
int initDelay=10; //初始化延时 int period=1;//初始化延迟过了之后,每秒的延时 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"); } },initDelay,period, TimeUnit.SECONDS);
这段代码的效果是:程序运行之后等10秒,然后输出第一次结果,之后每隔1秒输出一次结果。
为什么不推荐使用ScheduledThreadPool?
源码分析
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue()); }
可以看出ScheduledThreadPool的最大线程数(maximumPoolSize)为Integer的最大值2147483647,相当于可以无限的创建线程,而创建线程是需要内存的,这样就会造成内存溢出,而且一般的机器也没用那么大的内存给它创建这么大量的线程。
ThreadPoolExecutor创建线程池(十分推荐)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 12; i++) { final int finalI = i; threadPoolExecutor.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
ThreadPoolExecutor的七个参数详解
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { }
corePoolSize:核心线程数。这些线程一旦被创建不会被销毁,是一直存在的。线程池默认是没有线程的,当有任务到来了,就会通过ThreadFactory去创建线程,并一直存在。maximumPoolSize:最大线程数。非核心线程数=maximumPoolSize-corePoolSize,非核心线程数其实就是可扩容的线程数,可能会被销毁。keepAliveTime:非核心线程的空闲存活时间。当通过扩容生成的非核心线程数在keepAliveTime这个时间后还处于空闲状态,则会销毁这些非核心线程。unit:keepAliveTime的时间单位,例如:秒workQueue:等待区。当来了>corePoolSize的任务时会把任务存放在workQueue这个阻塞队列中,等待其他线程处理。threadFactory:线程工厂。创建线程的一种方式。handler:拒绝策略。当来了>最大线程数+workQueue的容量则会执行拒绝策略
workQueue
ArrayBlockingQueue:有界阻塞队列。队列有大小限制,当容量超过时则会触发扩容或者拒绝策略。
public ArrayBlockingQueue(int capacity) { this(capacity, false); }
LinkedBlockingQueue:无界阻塞队列,队列无大小限制,可能会造成内存溢出。
public LinkedBlockingQueue() { this(2147483647); }
handler
AbortPolicy:直接抛异常
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
DiscardPolicy:不作任何操作。默默丢弃任务
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }
DiscardOldestPolicy:丢掉存在时间最长的任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
CallerRunsPolicy:让提交任务的线程去处理任务
public static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
threadFactory
ThreadFactory threadFactory = Executors.defaultThreadFactory(); threadFactory.newThread(new Runnable() { @Override public void run() { System.out.println("threadFactory"); } }).start();
如何触发拒绝策略和线程池扩容?
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 26; i++) { //并发数26 final int finalI = i; threadPoolExecutor.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); } /** * 核心线程数=10,最大线程数=20,故可扩容线程数=20-10 * BlockingQueue的大小为5,故等待区的大小为5,也就是当并发数<=核心线程数+5不会扩容,并发数大于16才会扩容 * * 触发扩容:并发数>核心线程数+阻塞队列的大小 * 对于这段代码,如果来了26个并发,10个并发会被核心线程处理,5个会在等待区,剩下11个会因为等待区满了而触发扩容 * 因为这里最多能够扩容10个,这里却是11个,所以会触发拒绝策略 */
为什么这段代码会触发拒绝策略对于这段代码,如果来了26个并发,10个并发会被核心线程处理,5个会在等待区,剩下11个会因为等待区满了而触发扩容,但是又因为因为这里最多能够扩容10个,这里却是11个,所以会触发拒绝策略。
怎么触发扩容触发扩容:并发数>核心线程数(corePoolSize)+阻塞队列(workQueue)的大小
使用Java纯手写一个线程池下期文章链接https:///article/241589.htm
到此这篇关于非常适合新手学生的Java线程池超详细分析的文章就介绍到这了,更多相关Java 线程池内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。