发布网友 发布时间:2023-09-30 10:45
共1个回答
热心网友 时间:2024-12-02 09:53
使用Thread开启线程:
当然,一般我们会执行start方法。
若使用Thread开启线程:每一次子线程均需要经历创建和销毁的生命周期,性能不好。
为了解决这个问题,JDK设计出线程池。
JDK的BlockingQueue,天生实现的是生产者-消费者模型,即队列满了put队列会被阻塞;队列空了后get方法会被阻塞。
线程池中Worker线程开启后。使用while循环消费BlockingQueue中的Runnable。若while循环时得到的任务为空,那么便去关闭Worker线程。这也就是最大线程数和超过空闲时间的核心线程数能自动回收的原因。
核心线程数的空闲时间 KeepAliveTime 。其实就是阻塞队列获取Running的最大等待时间。当配置了该参数且超过最大等待时间,那么返回一个null任务。而worker线程的run方法中的while循环得到null时,便会结束这个worker线程。
poll获取到的元素为空,那么便会结束监听,worker线程的run方法执行完毕。
当返回null时,由“work线程将开启while循环的监听”可值,将结束worker线程的监听操作。
生产者向BlockingQueue中放入消息时,并没有使用put方法,而是使用的offer方法。
拒绝策略:因为offer方法返回false,说明阻塞队列已经满了,若最大线程数大于核心线程数,那么继续开启Worker线程。若开启的是最大线程数的Worker线程,那么就会执行配置的拒绝策略。
上文我们得知,生产者放入queue时使用的是offer方法,当阻塞队列满了之后,直接返回false。我们可以采用put的方式,将主线程阻塞。不在向BlockingQueue中填充任务。
JAVA并发(12)— Lock实现生产者消费者
JAVA并发(13)— ThreadPoolExecutor的实现原理(源码分析)