-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
81 lines (39 loc) · 7.68 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title></title>
<link href="/2023/10/31/%E7%BA%BF%E7%A8%8B%E6%B1%A0/"/>
<url>/2023/10/31/%E7%BA%BF%E7%A8%8B%E6%B1%A0/</url>
<content type="html"><![CDATA[<p>jdk<br>Java 8 的 parallel stream 功能,可以让我们很方便地并行处理集合中的元素,其背后是共享同一个 ForkJoinPool,默认并行度是CPU 核数 -1。对于 CPU 绑定的任务来说,使用这样的配置比较合适,但如果集合操作涉及同步 IO 操作的话(比如数据库操作、外部服务调用等),建议自定义一个ForkJoinPool(或普通线程池)。<br>改变线程池处理任务流程<br>Java 线程池是先用工作队列来存放来不及处理的任务,满了之后再扩容线程池。当我们的工作队列设置得很大时,最大线程数这个参数显得没有意义,因为队列很难满,或者到满的时候再去扩容线程池已经于事无补了。<br>我们有没有办法让线程池更激进一点,优先开启更多的线程,而把队列当成一个后备方案呢?<br>大致思路:<br>1.由于线程池在工作队列满了无法入队的情况下会扩容线程池,那么我们是否可以重写队列的 offer 方法,造成这个队列已满的假象呢?<br>2.由于我们 Hack 了队列,在达到了最大线程后势必会触发拒绝策略,那么能否实现一个自定义的拒绝策略处理程序,这个时候再把任务真正插入队列呢?<br>方案1<br>// extend LinkedBlockingQueue to force offer() to return false conditionally<br>BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>() {<br> private static final long serialVersionUID = -6903933921423432194L;<br> @Override<br> public boolean offer(Runnable e) {<br> // Offer it to the queue if there is 0 items already queued, else<br> // return false so the TPE will add another thread. If we return false<br> // and max threads have been reached then the RejectedExecutionHandler<br> // will be called which will do the put into the queue.<br> if (size() == 0) {<br> return super.offer(e);<br> } else {<br> return false;<br> }<br> }<br>};<br>ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1 /<em>core</em>/, 50 /<em>max</em>/,<br> 60 /<em>secs</em>/, TimeUnit.SECONDS, queue);<br>threadPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {<br> @Override<br> public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {<br> try {<br> // This does the actual put into the queue. Once the max threads<br> // have been reached, the tasks will then queue up.<br> executor.getQueue().put(r);<br> // we do this after the put() to stop race conditions<br> if (executor.isShutdown()) {<br> throw new RejectedExecutionException(<br> “Task “ + r + “ rejected from “ + e);<br> }<br> } catch (InterruptedException e) {<br> Thread.currentThread().interrupt();<br> return;<br> }<br> }<br>});<br>当向队列提交任务时,ThreadPoolExecutor将:<br>1.最初将线程数量扩展到核心大小<br>2.把任务offer进队列,(如果队列为空,它将被空闲线程处理)<br>3.如果队列已经有1个或多个元素,则offer(…)将返回false。<br>4.如果返回false,则增加池中的线程数,直到达到最大值<br>5.如果达到最大值,那么它调用RejectedExecutionHandler<br>6.RejectedExecutionHandler然后将任务放入队列中,由第一个可用线程以FIFO顺序处理。<br>方案评价:任务被执行的顺序问题,当任务1、任务2被放入队列,任务3在执行,假如任务3特别耗时,任务1和2就会不能即使被执行<br>方案2<br>重写 ourQueue(抽象的) ,并且将线程池设置到队列的属性中,ourQueue.setThreadPoolExecutor(tpe),这种方案会耦合队列和线程池<br>此时我们的offer方法就变成<br>int poolSize = tpe.getPoolSize();<br>int maximumPoolSize = tpe.getMaximumPoolSize();<br>if (poolSize >= maximumPoolSize || poolSize > tpe.getActiveCount()) {<br> return super.offer(e);<br>} else {<br> return false;<br>}<br>方案评价:因为通过访问 volatile属性(getActiveCount()、getPoolSize()) 或者 锁住 TPE 并遍历线程列表。此外,这里还存在并发条件,这些条件可能导致任务不正确地入队(也就是有序性,上一个任务进了队列,下一个任务却直接fork一个线程执行),或者在存在空闲线程时导致另一个线程分叉。<br>方案3:<br>解决方案是使用Java 7 LinkedTransferQueue并让offer()调用tryTransfer()。当有一个等待的消费者线程时,任务将被传递给该线程。否则,offer()将返回false, ThreadPoolExecutor将生成一个新线程。<br>BlockingQueue<Runnable> queue = new LinkedTransferQueue<Runnable>() {<br> @Override<br> public boolean offer(Runnable e) {<br> return tryTransfer(e);<br> }<br> };<br> ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 50, 60, TimeUnit.SECONDS, queue);<br> threadPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {<br> @Override<br> public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {<br> try {<br> executor.getQueue().put(r);<br> } catch (InterruptedException e) {<br> Thread.currentThread().interrupt();<br> }<br> }<br> });<br>方案的唯一缺点是LinkedTransferQueue是无界的。<br>tomcat也实现了这个idea<br>参考:<br><a href="https://github.com/apache/tomcat/blob/a801409b37294c3f3dd5590453fb9580d7e33af2/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java">https://github.com/apache/tomcat/blob/a801409b37294c3f3dd5590453fb9580d7e33af2/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java</a><br><a href="https://stackoverflow.com/questions/19528304/how-to-get-the-threadpoolexecutor-to-increase-threads-to-max-before-queueing">https://stackoverflow.com/questions/19528304/how-to-get-the-threadpoolexecutor-to-increase-threads-to-max-before-queueing</a></p>]]></content>
</entry>
<entry>
<title>Hello Hexo</title>
<link href="/2023/07/17/Hello-Hexo/"/>
<url>/2023/07/17/Hello-Hexo/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>Hello world! You</title>
<link href="/2023/07/17/test/"/>
<url>/2023/07/17/test/</url>
<content type="html"><![CDATA[<p><code>hsj</code><br>尊敬的招聘团队,</p><p>衷心感谢贵公司给予我参加面试的机会,并允许我对本次面试进行评价。</p>]]></content>
</entry>
<entry>
<title>友情链接</title>
<link href="/link/index.html"/>
<url>/link/index.html</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>分类</title>
<link href="/categories/index.html"/>
<url>/categories/index.html</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>标签页</title>
<link href="/tags/index.html"/>
<url>/tags/index.html</url>
<content type="html"><![CDATA[]]></content>
</entry>
</search>