目录
1. Semaphore信号量的使用
package com.test.threadpooldemo;
import java.util.concurrent.Semaphore;
public class ThreadPoolTest {
//信号量
private static Semaphore semaphore = new Semaphore(5); //5表示允许的个数,相当于放了5把锁
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
method();
}
}).start();
}
}
// 同时最多只允许5个线程过来
private static void method() {
try {
semaphore.acquire(); //获取一把锁
System.out.println("ThreadName = " + Thread.currentThread().getName() + " come in");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadName = " + Thread.currentThread().getName() + " come out");
semaphore.release(); //释放锁
}
}
输出结果:
> Task :ThreadPoolDemo:ThreadPoolTest.main()
ThreadName = Thread-0 come in
ThreadName = Thread-2 come in
ThreadName = Thread-4 come in
ThreadName = Thread-1 come in
ThreadName = Thread-5 come in
ThreadName = Thread-2 come out
ThreadName = Thread-0 come out
ThreadName = Thread-5 come out
ThreadName = Thread-4 come out
ThreadName = Thread-1 come out
ThreadName = Thread-8 come in
ThreadName = Thread-3 come in
ThreadName = Thread-6 come in
ThreadName = Thread-7 come in
ThreadName = Thread-10 come in
ThreadName = Thread-7 come out
ThreadName = Thread-8 come out
ThreadName = Thread-6 come out
ThreadName = Thread-10 come out
ThreadName = Thread-3 come out
ThreadName = Thread-13 come in
ThreadName = Thread-12 come in
ThreadName = Thread-9 come in
ThreadName = Thread-11 come in
ThreadName = Thread-14 come in
ThreadName = Thread-14 come out
ThreadName = Thread-12 come out
ThreadName = Thread-13 come out
ThreadName = Thread-11 come out
ThreadName = Thread-9 come out
ThreadName = Thread-18 come in
ThreadName = Thread-17 come in
ThreadName = Thread-16 come in
ThreadName = Thread-15 come in
ThreadName = Thread-19 come in
ThreadName = Thread-16 come out
ThreadName = Thread-19 come out
ThreadName = Thread-20 come in
ThreadName = Thread-15 come out
ThreadName = Thread-17 come out
ThreadName = Thread-18 come out
ThreadName = Thread-26 come in
ThreadName = Thread-22 come in
ThreadName = Thread-27 come in
ThreadName = Thread-21 come in
ThreadName = Thread-22 come out
ThreadName = Thread-27 come out
ThreadName = Thread-26 come out
ThreadName = Thread-24 come in
ThreadName = Thread-25 come in
ThreadName = Thread-20 come out
ThreadName = Thread-30 come in
ThreadName = Thread-28 come in
ThreadName = Thread-21 come out
ThreadName = Thread-29 come in
ThreadName = Thread-25 come out
ThreadName = Thread-28 come out
ThreadName = Thread-23 come in
ThreadName = Thread-30 come out
ThreadName = Thread-31 come in
ThreadName = Thread-32 come in
ThreadName = Thread-24 come out
ThreadName = Thread-33 come in
ThreadName = Thread-29 come out
ThreadName = Thread-34 come in
ThreadName = Thread-32 come out
ThreadName = Thread-31 come out
ThreadName = Thread-23 come out
ThreadName = Thread-33 come out
ThreadName = Thread-37 come in
ThreadName = Thread-36 come in
ThreadName = Thread-35 come in
ThreadName = Thread-38 come in
ThreadName = Thread-34 come out
ThreadName = Thread-39 come in
ThreadName = Thread-36 come out
ThreadName = Thread-37 come out
ThreadName = Thread-38 come out
ThreadName = Thread-41 come in
ThreadName = Thread-42 come in
ThreadName = Thread-35 come out
ThreadName = Thread-40 come in
ThreadName = Thread-43 come in
ThreadName = Thread-39 come out
ThreadName = Thread-44 come in
ThreadName = Thread-40 come out
ThreadName = Thread-41 come out
ThreadName = Thread-43 come out
ThreadName = Thread-46 come in
ThreadName = Thread-42 come out
ThreadName = Thread-48 come in
ThreadName = Thread-47 come in
ThreadName = Thread-49 come in
ThreadName = Thread-44 come out
ThreadName = Thread-45 come in
ThreadName = Thread-46 come out
ThreadName = Thread-50 come in
ThreadName = Thread-48 come out
ThreadName = Thread-45 come out
ThreadName = Thread-47 come out
ThreadName = Thread-49 come out
ThreadName = Thread-52 come in
ThreadName = Thread-53 come in
ThreadName = Thread-51 come in
ThreadName = Thread-54 come in
ThreadName = Thread-50 come out
ThreadName = Thread-55 come in
ThreadName = Thread-53 come out
ThreadName = Thread-54 come out
ThreadName = Thread-56 come in
ThreadName = Thread-57 come in
ThreadName = Thread-51 come out
ThreadName = Thread-52 come out
ThreadName = Thread-58 come in
ThreadName = Thread-59 come in
ThreadName = Thread-55 come out
ThreadName = Thread-60 come in
ThreadName = Thread-56 come out
ThreadName = Thread-59 come out
ThreadName = Thread-57 come out
ThreadName = Thread-58 come out
ThreadName = Thread-63 come in
ThreadName = Thread-62 come in
ThreadName = Thread-61 come in
ThreadName = Thread-64 come in
ThreadName = Thread-60 come out
ThreadName = Thread-65 come in
ThreadName = Thread-62 come out
ThreadName = Thread-63 come out
ThreadName = Thread-67 come in
ThreadName = Thread-64 come out
ThreadName = Thread-68 come in
ThreadName = Thread-61 come out
ThreadName = Thread-69 come in
ThreadName = Thread-66 come in
ThreadName = Thread-65 come out
ThreadName = Thread-67 come out
ThreadName = Thread-70 come in
ThreadName = Thread-68 come out
ThreadName = Thread-71 come in
ThreadName = Thread-72 come in
ThreadName = Thread-66 come out
ThreadName = Thread-69 come out
ThreadName = Thread-73 come in
ThreadName = Thread-74 come in
ThreadName = Thread-71 come out
ThreadName = Thread-74 come out
ThreadName = Thread-73 come out
ThreadName = Thread-72 come out
ThreadName = Thread-70 come out
ThreadName = Thread-79 come in
ThreadName = Thread-77 come in
ThreadName = Thread-76 come in
ThreadName = Thread-75 come in
ThreadName = Thread-78 come in
ThreadName = Thread-75 come out
ThreadName = Thread-76 come out
ThreadName = Thread-79 come out
ThreadName = Thread-80 come in
ThreadName = Thread-77 come out
ThreadName = Thread-82 come in
ThreadName = Thread-81 come in
ThreadName = Thread-83 come in
ThreadName = Thread-78 come out
ThreadName = Thread-84 come in
ThreadName = Thread-84 come out
ThreadName = Thread-81 come out
ThreadName = Thread-85 come in
ThreadName = Thread-86 come in
ThreadName = Thread-83 come out
ThreadName = Thread-80 come out
ThreadName = Thread-87 come in
ThreadName = Thread-82 come out
ThreadName = Thread-88 come in
ThreadName = Thread-89 come in
ThreadName = Thread-88 come out
ThreadName = Thread-87 come out
ThreadName = Thread-86 come out
ThreadName = Thread-89 come out
ThreadName = Thread-93 come in
ThreadName = Thread-85 come out
ThreadName = Thread-92 come in
ThreadName = Thread-91 come in
ThreadName = Thread-94 come in
ThreadName = Thread-90 come in
ThreadName = Thread-92 come out
ThreadName = Thread-93 come out
ThreadName = Thread-94 come out
ThreadName = Thread-90 come out
ThreadName = Thread-98 come in
ThreadName = Thread-91 come out
ThreadName = Thread-97 come in
ThreadName = Thread-95 come in
ThreadName = Thread-96 come in
ThreadName = Thread-99 come in
ThreadName = Thread-98 come out
ThreadName = Thread-97 come out
ThreadName = Thread-96 come out
ThreadName = Thread-95 come out
ThreadName = Thread-99 come out
2. Executor的使用
package com.test.threadpooldemo;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ThreadPoolTest2 {
private static Executor executor = Executors.newCachedThreadPool(); //缓存线程池
private static Executor executor2 = Executors.newFixedThreadPool(5); //固定线程个数的线程池
private static Executor executor3 = Executors.newScheduledThreadPool(5); //计划任务线程池
private static Executor executor4 = Executors.newSingleThreadExecutor(); //单个线程的线程池
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
executor2.execute(new Runnable() {
@Override
public void run() {
method();
}
});
}
}
// 同时最多只允许5个线程过来
private static void method() {
try {
System.out.println("ThreadName = " + Thread.currentThread().getName() + " come in");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadName = " + Thread.currentThread().getName() + " come out");
}
}
输出结果:
>Task :ThreadPoolDemo:ThreadPoolTest2.main()
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-5 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-5 come in
ThreadName = pool-2-thread-1 come in
ThreadName = pool-2-thread-4 come in
ThreadName = pool-2-thread-3 come in
ThreadName = pool-2-thread-2 come in
ThreadName = pool-2-thread-3 come out
ThreadName = pool-2-thread-4 come out
ThreadName = pool-2-thread-1 come out
ThreadName = pool-2-thread-2 come out
ThreadName = pool-2-thread-5 come out
3. 阻塞队列
阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。
其中BlockingQueue接口中成对出现的方法:
- add(E) 和 remove(Object)
- offer(E) 和 poll(long, TimeUnit)
- put(E) 和 take()
其中只有put(E)和take()操作是阻塞的,其他的方法属于非阻塞的
方法/处理方式 | 抛出异常 | 返回特殊值 | 一直阻塞 | 超时退出 |
---|---|---|---|---|
插入方法 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除方法 | remove() | poll() | take() | poll(time, unit) |
检查方法 | element() | peek() | 不可用 | 不可用 |
- 抛出异常:当队列满时,如果再往队列里插入元素,会抛出IllegalStateException(“Queuefull”)异常。当队列空时,从队列里获取元素会抛出 NoSuchElementException 异常。
- 返回特殊值:当往队列插入元素时,会返回元素是否插入成功,成功返回true。如果是移除方法,则是从队列里取出一个元素,如果没有则返回 null。
- 一直阻塞:当阻塞队列满时,如果生产者线程往队列里 put 元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断退出。当队列空时,如果消费者线程从队列里 take 元素,队列会阻塞住消费者线程,直到队列不为空。
- 超时退出:当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定的时间,生产者线程就会退出。
常用阻塞队列:
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
-
ArrayBlockingQueue
是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证线程公平的访问队列,所谓公平访问队列是指阻塞的线程,可以按照阻塞的先后顺序访问队列,即先阻塞线程先访问队列。非公平性是对先等待的线程是非公平的,当队列可用时,阻塞的线程都可以争夺访问队列的资格,有可能先阻塞的线程最后才访问队列。初始化时有参数可以设置 -
LinkedBlockingQueue
是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。Array 实现和 Linked 实现的区别
- 队列中锁的实现不同
ArrayBlockingQueue 实现的队列中的锁是没有分离的,即生产和消费用的是同一个锁;
LinkedBlockingQueue 实现的队列中的锁是分离的,即生产用的是 putLock,消费是 takeLock - 在生产或消费时操作不同
ArrayBlockingQueue 实现的队列中在生产和消费的时候,是直接将枚举对象插入或移除的;
LinkedBlockingQueue 实现的队列中在生产和消费的时候,需要把枚举对象转换为 Node进行插入或移除,会影响性能 - 队列大小初始化方式不同
ArrayBlockingQueue 实现的队列中必须指定队列的大小;
LinkedBlockingQueue 实现的队列中可以不指定队列的大小,但是默认是Integer.MAX_VALUE
- 队列中锁的实现不同
-
PriorityBlockingQueue
PriorityBlockingQueue 是一个支持优先级的无界阻塞队列。默认情况下元素采取自然顺序升序排列。也可以自定义类实现 compareTo()方法来指定元素排序规则,或者初始化 PriorityBlockingQueue 时,指定构造参数 Comparator 来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。 -
DelayQueue
是一个支持延时获取元素的无界阻塞队列。队列使用 PriorityQueue 来实现。队列中的元素必须实现 Delayed 接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素。
DelayQueue 非常有用,可以将 DelayQueue 运用在以下应用场景。
缓存系统的设计:
可以用 DelayQueue 保存缓存元素的有效期,使用一个线程循环查询 DelayQueue,一旦能从 DelayQueue 中获取元素时,表示缓存有效期到了。 -
SynchronousQueue
是一个不存储元素的阻塞队列。每一个 put 操作必须等待一个 take 操作,否则不能继续添加元素。SynchronousQueue 可以看成是一个传球手,负责把生产者线程处理的数据直接传递给消费者线程。队列本身并不存储任何元素,非常适合传递性场景。SynchronousQueue 的吞吐量高于 LinkedBlockingQueue 和ArrayBlockingQueue。 -
LinkedTransferQueue
多了 tryTransfer 和 transfer 方法,
(1)transfer 方法
如果当前有消费者正在等待接收元素(消费者使用 take()方法或带时间限制的 poll()方法时),transfer 方法可以把生产者传入的元素立刻 transfer(传输)给消费者。如果没有消费者在等待接收元素,transfer 方法会将元素存放在队列的 tail 节点,并等到该元素被消费者消费了才返回。
(2)tryTransfer 方法
tryTransfer 方法是用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回 false。和 transfer 方法的区别是 tryTransfer 方法无论消费者是否接收,方法立即返回,而 transfer 方法是必须等到消费者消费了才返回。 -
LinkedBlockingDeque
LinkedBlockingDeque 是一个由链表结构组成的双向阻塞队列。所谓双向队列指的是可以从队列的两端插入和移出元素。双向队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。
多了 addFirst、addLast、offerFirst、offerLast、peekFirst 和 peekLast 等方法,以 First 单词结尾的方法,表示插入、获取(peek)或移除双端队列的第一个元素。以 Last 单词结尾的方法,表示插入、获取或移除双端队列的最后一个元素。另外,插入方法 add 等同于 addLast,移除方法 remove 等效于 removeFirst。但是 take 方法却等同于 takeFirst,不知道是不是 JDK 的 bug,使用时还是用带有 First和 Last 后缀的方法更清楚。在初始化 LinkedBlockingDeque 时可以设置容量防止其过度膨胀。另外,双向阻塞队列可以运用在“工作窃取”模式中。
4、线程池LinkedTransferQueue
4.1为什么要用线程池?
Java 中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池。在开发过程中,合理地使用线程池能够带来 3个好处。
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。 如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。线程池技术正是关注如何缩短或调整 T1,T3 时间的技术,从而提高服务器程序性能的。它把 T1,T3 分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有 T1,T3 的开销了。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
4.2ThreadPoolExecutor 的类关系
Executor 是一个接口,它是 Executor 框架的基础,它将任务的提交与任务的执行分离开来。
ExecutorService 接口继承了 Executor,在其上做了一些 shutdown()、submit()的扩展,可以说是真正的线程池接口;
AbstractExecutorService 抽象类实现了 ExecutorService 接口中的大部分方法;
ThreadPoolExecutor 是线程池的核心实现类,用来执行被提交的任务。
ScheduledExecutorService 接口继承了 ExecutorService 接口,提供了带"周期执行"功能 ExecutorService;
ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。ScheduledThreadPoolExecutor 比 Timer 更灵活,功能更强大。
4.3 线程池的创建各个参数含义
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long
keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
参数1:corePoolSize–>表示核心池大小
参数2:maximumPoolSize–>表示最大线程池上限个数
参数3:keepAliveTime–>表示任务执行完成之后,要裁员的延时
参数4:unit–>表示时间单位
参数5:workQueue–>表示用于存储任务的工作队列
参数6:threadFactory–>表示线程工厂,用于创建线程
参数7:handler --> 拒绝策略
-
corePoolSize
线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于 corePoolSize;
如果当前线程数为 corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;
如果执行了线程池的 prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。 -
maximumPoolSize
线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于 maximumPoolSize -
keepAliveTime
线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间。默认情况下,该参数只在线程数大于 corePoolSize 时才有用 -
TimeUnit
keepAliveTime 的时间单位 -
workQueue
workQueue 必须是 BlockingQueue 阻塞队列。当线程池中的线程数超过它的corePoolSize 的时候,线程会进入阻塞队列进行阻塞等待。通过workQueue,线程池实现了阻塞功能。
一般来说,我们应该尽量使用有界队列,因为使用无界队列作为工作队列会对线程池带来如下影响。
1)当线程池中的线程数达到 corePoolSize 后,新任务将在无界队列中等待,因此线程池中的线程数不会超过 corePoolSize。
2)由于 1,使用无界队列时 maximumPoolSize 将是一个无效参数。
3)由于 1 和 2,使用无界队列时 keepAliveTime 将是一个无效参数。
4)更重要的,使用无界 queue 可能会耗尽系统资源,有界队列则有助于防止资源耗尽,同时即使使用有界队列,也要尽量控制队列的大小在一个合适的范围。 -
threadFactory
创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名,当然还可以更加自由的对线程做更多的设置,比如设置所有的线程为守护线程。
Executors 静态工厂里默认的 threadFactory,线程的命名规则是“pool-数字-thread-数字”。 -
RejectedExecutionHandler
线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了 4 种策略:
(1)AbortPolicy:直接抛出异常,默认策略;
(2)CallerRunsPolicy:用调用者所在的线程来执行任务;
(3)DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行 当前任务;
(4)DiscardPolicy:直接丢弃任务;
当然也可以根据应用场景实现 RejectedExecutionHandler 接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
4.4 线程池的工作机制
1)如果当前运行的线程少于 corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁)。
2)如果运行的线程等于或多于 corePoolSize,则将任务加入 BlockingQueue。
3)如果无法将任务加入 BlockingQueue(队列已满),则创建新的线程来处理任务。
4)如果创建新线程将使当前运行的线程超出 maximumPoolSize,任务将被拒绝,并调用 RejectedExecutionHandler.rejectedExecution()方法。
假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序应该是怎样的?
1)首先执行任务 1、2、3,
2)然后任务 4~13 被放入队列。
3)这时候队列满了,任务 14、15、16 会被马上执行,
4)而任务 17~20 则会抛出异常。
5)最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。
4.5 提交任务
往线程池提交任务的两种方式:
- ThreadPoolExecutor类中的 execute(Runnable)
- ExecutorService类中的 submit方法,submit三种方式如下:
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
execute和submit的区别:execute方法没有返回值,submit有返回值
execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程
池执行成功。
submit()方法用于提交需要返回值的任务。线程池会返回一个 future 类型的对象,通过这个 future 对象可以判断任务是否执行成功,并且可以通过 future的 get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
4.6 关闭线程池
可以通过调用线程池的 shutdown
或 shutdownNow
方法来关闭线程池。它们的原理是遍历线程池中的工作线程,然后逐个调用线程的 interrupt 方法来中断线程,所以无法响应中断的任务可能永远无法终止。但是它们存在一定的区别,shutdownNow 首先将线程池的状态设置成 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而 shutdown 只是将线程池的状态设置成 SHUTDOWN 状态,然后中断所有没有正在执行任务的线程。
只要调用了这两个关闭方法中的任意一个,isShutdown 方法就会返回 true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用 isTerminaed 方法会返回 true。至于应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用 shutdown 方法来关闭线程池,如果任务不一定要执行完,则可以调用 shutdownNow 方法。
Java终止线程的三种方式
Java终止线程的方式
停止一个线程通常意味着在线程处理任务完成之前停掉正在做的操作,也就是放弃当前的操作。启动一个线程可以调用start();那么停止一个线程可以怎么处理呢?
-
interrupt()
最正确的停止线程的方式是使用 interrupt。
但 interrupt仅仅起到通知被停止线程的作用。
而对于被停止的线程而言,它拥有完全的自主权,它既可以选择立即停止,也可以选择一段时间后停止,也可以选择不停止。 -
shutdown()
调用 shutdown() 方法之后线程池不会立刻就被关闭,因为这时线程池中可能还有很多任务正在被执行,或是任务队列中有大量正在等待被执行的任务,调用 shutdown() 方法后线程池会在执行完正在执行的任务和队列中等待的任务后才彻底关闭。 -
shutdownNow()
如果想要马上关闭线程池,不管正在执行的任务和排队等待的任务,那么shutdownNow则是你最好的选择,强就强在NOW。 -
isTerminated()
这个方法可以检测 线程池是否真正“终结” 了,这不仅代表线程池已关闭,同时代表线程池中的所有任务都已经都执行完毕了。假如此时已经调用了 shutdown 方法,但是有一个线程依然在执行任务,那么此时调用isShutdown 方法返回的是 true ,而调用 isTerminated 方法返回的便是 false ,因为线程池中还有任务正在在被执行,线程池并没有真正“终结”。
直到所有任务都执行完毕了,调用 isTerminated() 方法才会返回 true,这表示线程池已关闭并且线程池内部是空的,所有剩余的任务都执行完毕了。
4.7 合理地配置线程池
要想合理地配置线程池,就必须首先分析任务特性,可以从以下几个角度来分析。
- 任务的性质:CPU 密集型任务、IO 密集型任务和混合型任务。
- 任务的优先级:高、中和低。
- 任务的执行时间:长、中和短。
- 任务的依赖性:是否依赖其他系统资源,如数据库连接。
性质不同的任务可以用不同规模的线程池分开处理。
CPU 密集型任务应配置尽可能小的线程,如配置 Ncpu+1
个线程的线程池。
由于 IO 密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*Ncpu
。
混合型的任务,如果可以拆分,将其拆分成一个 CPU 密集型任务和一个 IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐量将高于串行执行的吞吐量。如果这两个任务执行时间相差太大,则没必要进行分解。可以通过 Runtime.getRuntime().availableProcessors()
方法获得当前设备的CPU 个数。
优先级不同的任务可以使用优先级队列 PriorityBlockingQueue
来处理。它可以让优先级高的任务先执行。
执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先级队列,让执行时间短的任务先执行。
建议使用有界队列。有界队列能增加系统的稳定性和预警能力,可以根据需要设大一点儿,比如几千。
如果当时我们设置成无界队列,那么线程池的队列就会越来越多,有可能会撑满内存,导致整个系统不可用,而不只是后台任务出现问题。
线程不是越多越好,google工程师给了一个推荐值:最大线程的个数=CPU核心数 + 1。比如cpu核心数为4,则线程的个数为5。
为什么+ 1呢?
因为会产生虚拟内存,在线程过程中可能会产生页缺失的情况,所以操作系统为了防止cpu空闲,+1就是为了保证任意一个时刻cpu都不是空闲的,最大程度的利用cpu资源。
package com.test.threadpooldemo;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolTest3 {
public static void main(String[] args) {
//BlockingQueue<E> 单端队列
//BlockingDeque<E> 双端队列
LinkedBlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>(100); //100是该容器的最大上限
ThreadFactory threadFactory = new ThreadFactory() {
//线程安全的int包装类
AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public Thread newThread(Runnable runnable) {
//创建一个线程,然后将runnable赋值给该线程
Thread thread = new Thread(runnable);
thread.setName("MyThread=" + atomicInteger.getAndIncrement()); //getAndIncrement: 先获取值在自增,功能类似于i++
return thread;
}
};
/**
* ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
* BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
* 参数1:corePoolSize-->表示核心池大小
* 参数2:maximumPoolSize-->表示最大线程池上限个数
* 参数3:keepAliveTime-->表示任务执行完成之后,要裁员的延时
* 参数4:unit-->表示时间单位
* 参数5:workQueue-->表示用于存储任务的工作队列
* 参数6:threadFactory-->表示线程工厂,用于创建线程
*
*/
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.SECONDS, blockingQueue, threadFactory);
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
method();
}
});
}
}
private static void method() {
try {
System.out.println("ThreadName = " + Thread.currentThread().getName() + " come in");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadName = " + Thread.currentThread().getName() + " come out");
}
}
运行结果:
> Task :ThreadPoolDemo:ThreadPoolTest3.main()
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=3 come out
上面代码中设置的Thread集合为10,workQueue任务队列为100,则可以最多创建10+100=110个线程,如果创建超过110个线程就会报错。
如果将程序中的for循环进行稍微更改下:
for (int i = 0; i < 120; i++) {
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
method();
}
});
}
执行结果就会报如下问题:
> Task :ThreadPoolDemo:ThreadPoolTest3.main()
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=5 come in
ThreadName = MyThread=6 come in
ThreadName = MyThread=7 come in
ThreadName = MyThread=8 come in
ThreadName = MyThread=9 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=5 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=0 come in
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.test.threadpooldemo.ThreadPoolTest3$2@6bc7c054 rejected from java.util.concurrent.ThreadPoolExecutor@232204a1[Running, pool size = 10, active threads = 10, queued tasks = 100, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.test.threadpooldemo.ThreadPoolTest3.main(ThreadPoolTest3.java:48)
ThreadName = MyThread=6 come out
ThreadName = MyThread=5 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=2 come in
ThreadName = MyThread=5 come in
ThreadName = MyThread=6 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=8 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=5 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=7 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=5 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=5 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=9 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=5 come out
ThreadName = MyThread=5 come in
ThreadName = MyThread=6 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=8 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=8 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=5 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=8 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=6 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=6 come in
ThreadName = MyThread=5 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=1 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=1 come in
ThreadName = MyThread=5 come out
ThreadName = MyThread=5 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=3 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=7 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=7 come in
ThreadName = MyThread=0 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=8 come in
ThreadName = MyThread=2 come out
ThreadName = MyThread=2 come in
ThreadName = MyThread=3 come out
ThreadName = MyThread=3 come in
ThreadName = MyThread=9 come out
ThreadName = MyThread=5 come out
ThreadName = MyThread=9 come in
ThreadName = MyThread=6 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=6 come in
ThreadName = MyThread=5 come in
ThreadName = MyThread=1 come in
ThreadName = MyThread=0 come out
ThreadName = MyThread=0 come in
ThreadName = MyThread=4 come out
ThreadName = MyThread=4 come in
ThreadName = MyThread=7 come out
ThreadName = MyThread=7 come in
ThreadName = MyThread=8 come out
ThreadName = MyThread=2 come out
ThreadName = MyThread=6 come out
ThreadName = MyThread=9 come out
ThreadName = MyThread=5 come out
ThreadName = MyThread=3 come out
ThreadName = MyThread=1 come out
ThreadName = MyThread=0 come out
ThreadName = MyThread=4 come out
ThreadName = MyThread=7 come out
分发器总结:
对于同步请求,分发器只记录请求,用于判断IdelRunnable是否需要执行
对于异步请求,向分发器中提交请求:
Q:如何决定将请求放入ready还是running?
A: 如果当前正在请求数为64,则将请求放入ready等待执行,如果小于64,但是已经存在同一域名主机的请求5个,也会放入ready;否则放入running队列立即执行;
Q:从ready移动running的条件是什么?
A:每个请求执行完成就会从running移除,同时进行第一步相同逻辑的判断,决定是否移动。
Q:分发器线程池的工作行为?
A:无等待,最大并发(SynchronousQueue)