温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java中的线程池有什么用

发布时间:2021-08-20 09:08:26 来源:亿速云 阅读:135 作者:chen 栏目:云计算

这篇文章主要讲解了“Java中的线程池有什么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中的线程池有什么用”吧!

Java中的线程池

【1】使用线程池的好处:

1)降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2)提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行。
3)提高线程的可管理性。线程池可以进行统一分配、调优和监控线程。

【2】构造方法:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler);

参数说明:

	1)corePoolSize:核心池的大小。
	
		1)在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务。
		2)默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务。
			注意:即使其它空闲的线程能够执行新任务也会去创建线程,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。
		3)调用prestartAllCoreThreads()或prestartCoreThread()方法来预创建线程,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。
		
		
	2)workQueue:任务缓存队列,是一个阻塞队列,用来存储等待执行的任务;类型为BlockingQueue<Runnable>,通常可以取下面4种类型:
	
		1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
		2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQueue。
			eg:静态工厂方法Executors.newFixedThreadPool()就是使用的这个队列。
		3)SynchronousQueue:这个队列不会保存提交的任务,而是直接新建一个线程来执行新来的任务。
			说明:每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue。
			eg:静态工厂方法Executors.newCachedThreadPool使用的就是这个队列。
		4)PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
		
		说明:
			1>一般使用LinkedBlockingQueue和SynchronousQueue
			2>建议使用有界队列,有界队列能增加系统的稳定性。
				eg:如果线程池里的工作线程全部阻塞,任务积压在线程池里,如果设置成无界队列,那么这个队列会越来越大,有可能会撑满内存,导致整个系统不可用。

		
	3)maximumPoolSize:线程池中允许创建的最大线程数。
	
		1)如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程来执行任务。
		2)如果使用了无界的任务队列,则这个参数就不起什么作用了(队列默认的大小是:Integer.MAX_VALUE,在队列未满之前,线程池是不会再去创建新线程了)。
	
	
	4)RejectedExecutionHandler:任务拒绝策略,当任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
	
		1)ThreadPoolExecutor.AbortPolicy:		丢弃任务并抛出RejectedExecutionException异常,默认使用该策略。
		2)ThreadPoolExecutor.DiscardPolicy:	丢弃任务,但是不抛出异常;会导致被丢弃的任务无法再次被执行
		3)ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程);会导致被丢弃的任务无法再次被执行
		4)ThreadPoolExecutor.CallerRunsPolicy:	由调用线程处理该任务;主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 

		说明:也可以实现RejectedExecutionHandler接口来自定义策略。


	5)keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。
	
		默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用。
		但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
		
		
	6)TimeUnit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
	
		TimeUnit.DAYS;				天
		TimeUnit.HOURS;				小时
		TimeUnit.MINUTES;			分钟
		TimeUnit.SECONDS;			秒
		TimeUnit.MILLISECONDS;		毫秒
		TimeUnit.MICROSECONDS;		微妙
		TimeUnit.NANOSECONDS;		纳秒

		
	7)ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

【3】其它方法:

任务的提交:
	execute(Runnable command):	提交后没有返回值,故无法判断任务是否被线程池执行成功。
		
	submit():	提交后返回一个Future对象,通过这个future对象可以判断任务是否执行成功。
		通过future的get()方法来获取返回值,该方法会阻塞当前线程直到任务完成。
		get(long timeout, TimeUnit unit)方法:阻塞当前线程一段时间后立即返回,这时候任务可能没有执行完。



线程池容量的动态调整:
	setCorePoolSize()		设置核心池的大小
	setMaximumPoolSize()	设置线程池最大能创建的线程数

线程池的关闭:

	原理:遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。
	
	shutdown()		
		1>将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
		2>不再接受新的任务,但是不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止。
	shutdownNow()	
		1>首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并且清空任务缓存队列,并返回等待执行任务的列表.

	说明:
		1)只要调用了这两个关闭方法中的任意一个,isShutdown方法就会返回true。
		2)当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。

【4】线程池的状态:

// RUNNING状态:线程池正常运行,可以接受新的任务并处理队列中的任务
private static final int RUNNING    = -1 << COUNT_BITS;
// SHUTDOWN状态:不再接受新任务,但是会执行队列中的任务
private static final int SHUTDOWN   =  0 << COUNT_BITS;
// STOP状态:不再接受新任务,不处理队列中的任务,中断正在处理的任务
private static final int STOP       =  1 << COUNT_BITS;
// 过渡状态:所有的任务都执行完了,线程池已经没有有效的线程了,此时线程池的状态为过渡状态,并且将要调用terminated()方法
private static final int TIDYING    =  2 << COUNT_BITS;
// 终止状态:terminated()方法调用完成后的状态
private static final int TERMINATED =  3 << COUNT_BITS;

1>当线程池刚创建后,线程池处于RUNNING状态,可以接受新的任务并处理队列中的任务
2>如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
3>如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
4>当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

【5】线程池的处理流程:

ThreadPoolExecutor执行execute方法分下面4种情况。
	1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁)。
	2)如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
	3)如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。
	4)如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用	RejectedExecutionHandler.rejectedExecution()方法。

感谢各位的阅读,以上就是“Java中的线程池有什么用”的内容了,经过本文的学习后,相信大家对Java中的线程池有什么用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI