多线程(五)
1、案例----线程池
因为进程创建销毁时比较低效(内存的申请和释放),所以引入了线程。线程共享内存资源,新的线程可以利用之前的资源而不需要重新申请,此时效率会提高。
但若创建线程的速率进一步变频繁了,此时线程的创建和销毁仍不可忽视。想要进一步优化速度,采用线程池。
提问:为什么在线程池中取比创建线程快?
答:创建线程实在操作系统的内核中完成的,涉及到用户态到内核态的切换操作,这个操作存在一定开销。
从线程池取线程,把线程放回线程池,这是纯用户态的实现的逻辑。从系统这里创建进程,则是用户态到内核态共同完成的逻辑。
线程池最大的好处就是减少每次启动、销毁线程的损耗。
(1)线程池的使用
(2)自己实现线程池
=》一个线程池可以同时提交N个任务。
=》对应的线程池中有M个线程来负责完成这N个任务。
思路:生产者消费者模型,可以解决将N个任务分给M个线程的问题。先应用一个阻塞队列,每个被提交的任务,都放在阻塞队列中。用M个线程来取队列元素,如果队列空了,M个线程阻塞等待;如果队列不为空,每个线程都取任务并执行,再来取下一个任务......知道队列为空。
以下是一个固定线程池数目的线程池的实现:
执行结果:
线程池的优点:
=》 降低资源消耗。减少线程的创建和销毁带来的性能开销。
=》提高响应速度。当有任务来时,可以直接使用,不用等待创建线程。
=》可管理性。进行统一的分配,监控,避免大量线程因互相抢占系统资源导致阻塞现象。
(3)JAVA线程池有几个核心的参数,这几个参数的作用是:
->corePoolSize:核心线程数。当提交一个新的任务到线程池,如果当前线程池运行的线程数(包括闲置的线程)小于核心线程数,则会创建一个新的线程作为核心线程来执行该任务。
->maximumPoolSize:线程池允许的最大线程数。当提交一个新的任务到线程池,如果当前线程池运行的线程数(包括闲置的线程)大于核心线程数,但小于允许的最大线程数,并且等待队列满时,会创建一个新的线程处理该任务。
->keepAliveTime:当线程池中线程数量大于核心线程数时,限制的线程最长存活的时间。
->unit:时间单位。
->workQueue:保存任务的队列,当线程数大于核心线程数时,新的任务将保存到该队列。
->threadFactory:线程工厂,线程池中的线程都是通过该工厂创建的。
->handler: 任务拒绝执行策略。拒绝策略如下:
=》AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
=》DiscardPolicy:丢弃新来的任务。
=》DiscardOldestPolicy:丢弃最先来的任务,然后重新尝试执行任务。
=》CallerRunsPolicy:把该任务交给添加此任务的线程来执行。
沫沫198: 厉害厉害,大佬好牛
CSDN-Ada助手: 推荐 Java 技能树:https://edu.csdn.net/skill/java?utm_source=AI_act_java