您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

Java线程池如何创建

2024/4/25 5:40:24发布14次查看
线程池的好处可以实现线程的复用,避免重新创建线程和销毁线程。创建线程和销毁线程对cpu的开销是很大的。
可以限制最大可创建的线程数,可根据自己的机器性能动态调整线程池参数,提高应用性能。
提供定时执行、并发数控制等功能。
统一管理线程。
创建线程池的五种方式1:缓存线程池(不推荐)
2:固定容量线程池(不推荐)
3:单个线程池(不推荐)
4:定时任务线程池(不推荐)
5:通过threadpoolexecutor构造方法创建线程池(阿里巴巴开发手册十分推荐)
前面4种创建线程池的方式都是通过executors的静态方法来创建。
缓存线程池cachedthreadpool executorservice executorservice = executors.newcachedthreadpool(); 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); } }); }
为什么不推荐使用缓存线程池?
源码分析
public static executorservice newcachedthreadpool() { return new threadpoolexecutor(0, 2147483647, 60l, timeunit.seconds, new synchronousqueue()); }
public threadpoolexecutor(int corepoolsize, int maximumpoolsize, long keepalivetime, timeunit unit, blockingqueue<runnable> workqueue) { this(corepoolsize, maximumpoolsize, keepalivetime, unit, workqueue, executors.defaultthreadfactory(), defaulthandler); }
通过上面两个代码片段,我们可以看出cachedthreadpool的maximumpoolsize为integer的最大值2147483647,相当于可以无限的创建线程,而创建线程是需要内存的,这样就会造成内存溢出,而且一般的机器也没用那么大的内存给它创建这么大量的线程。
固定容量线程池fixedthreadpoolnewfixedthreadpool(int num),num就是我们要指定的固定线程数量
executorservice executorservice = executors.newfixedthreadpool(5); 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); } }); }
输出:
pool-1-thread-5<thread->run>4
pool-1-thread-4<thread->run>3
pool-1-thread-5<thread->run>5
pool-1-thread-3<thread->run>2
pool-1-thread-3<thread->run>8
pool-1-thread-3<thread->run>9
pool-1-thread-2<thread->run>1
pool-1-thread-1<thread->run>0
pool-1-thread-5<thread->run>7
pool-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的容量则会执行拒绝策略
workqueuearrayblockingqueue:有界阻塞队列。队列有大小限制,当容量超过时则会触发扩容或者拒绝策略。
public arrayblockingqueue(int capacity) { this(capacity, false); }
linkedblockingqueue:无界阻塞队列,队列无大小限制,可能会造成内存溢出。
public linkedblockingqueue() { this(2147483647); }
handlerabortpolicy:直接抛异常
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纯手写一个线程池
以上就是java线程池如何创建的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product