Java多线程研究05-ThreadPoolExecutor中workQueue、thre。。。

更新时间:2023-05-26 13:32:42 阅读: 评论:0

Java多线程研究05-ThreadPoolExecutor中workQueue、thre。。。
我们继续讨论ThreadPoolExecutor线程池。上篇⽂章给出的最简单的ThreadPoolExecutor线程池的使⽤⽅式中,我们只采⽤了ThreadPoolExecutor最简单的⼀个构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
实际上ThreadPoolExecutor线程池有很多种构造函数,其中最复杂的⼀种构造函数是:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
在上⽂中我们还没有介绍的workQueue、threadFactory和handler参数,将是本⽂讲解的重点。
⼀:ThreadFactory的使⽤
线程池最主要的⼀项⼯作,就是在满⾜某些条件的情况下创建线程。⽽在ThreadPoolExecutor线程池中,创建线程的⼯作交给ThreadFactory来完成。要使⽤线程池,就必须要指定ThreadFactory。
类似于上⽂中,如果我们使⽤的构造函数时并没有指定使⽤的ThreadFactory,这个时候ThreadPoolExecutor会使⽤⼀个默认的ThreadFactory:DefaultThreadFactory。(这个类在Executors⼯具类中)
冬瓜怎么炒当然,在某些特殊业务场景下,还可以使⽤⼀个⾃定义的ThreadFactory线程⼯⼚,如下代码⽚段:
import urrent.ThreadFactory;
/**
* 测试⾃定义的⼀个线程⼯⼚
*/
public class TestThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
}
⼆:线程池的等待队列
在使⽤ThreadPoolExecutor线程池的时候,需要指定⼀个实现了BlockingQueue接⼝的任务等待队列。在ThreadPoolExecutor线程池的API⽂档中,⼀共推荐了三种等待队列,它们是:SynchronousQueue、LinkedBlockingQueue和ArrayBlockingQueue;
队列和栈
● 队列:是⼀种特殊的线性结构,允许在线性结构的前端进⾏删除/读取操作;允许在线性结构的后端进⾏插⼊操作;这种线性结构具
有“先进先出”的操作特点:
但是在实际应⽤中,队列中的元素有可能不是以“进⼊的顺序”为排序依据的。例如我们将要讲到的PriorityBlockingQueue队列。
● 栈:栈也是⼀种线性结构,但是栈和队列相⽐只允许在线性结构的⼀端进⾏操作,⼊栈和出栈都是在⼀端完成。
2.1有限队列
● SynchronousQueue:
“是这样 ⼀种阻塞队列,其中每个 put 必须等待⼀个 take,反之亦然。同步队列没有任何内部容量。翻译⼀下:这是⼀个内部没有任何容量的阻塞队列,任何⼀次插⼊操作的元素都要等待相对的删除/读取操作,否则进⾏插⼊操作的线程就要⼀直等待,反之亦然。
SynchronousQueue<Object> queue = new SynchronousQueue<Object>();
// 不要使⽤add,因为这个队列内部没有任何容量,所以会抛出异常“IllegalStateException”
// queue.add(new Object());
/
/ 操作线程会在这⾥被阻塞,直到有其他操作线程取⾛这个对象
queue.put(new Object());
● ArrayBlockingQueue:
⼀个由数组⽀持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进⾏排序。新元素插⼊到队列的尾部,队列获取操作则是从队列头部开始获得元素。这是⼀个典型的“有界缓存区”,固定⼤⼩的数组在其中保持⽣产者插⼊的元素和使⽤者提取的元素。⼀旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放⼊元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
// 我们创建了⼀个ArrayBlockingQueue,并且设置队列空间为2
ArrayBlockingQueue<Object> arrayQueue = new ArrayBlockingQueue<Object>(2);
// 插⼊第⼀个对象
arrayQueue.put(new Object());
// 插⼊第⼆个对象
arrayQueue.put(new Object());
// 插⼊第三个对象时,这个操作线程就会被阻塞。
arrayQueue.put(new Object());
// 请不要使⽤add操作,和SynchronousQueue的add操作⼀样,它们都使⽤了AbstractQueue中的add实现
2.2⽆限队列
● LinkedBlockingQueue:
LinkedBlockingQueue是我们在ThreadPoolExecutor线程池中常⽤的等待队列。它可以指定容量也可以不指定容量。由于它具有“⽆限容量”的特性,所以我还是将它归⼊了⽆限队列的范畴(实际上任何⽆限容量的队列/栈都是有容量的,这个容量就是
Integer.MAX_VALUE)。
LinkedBlockingQueue的实现是基于链表结构,⽽不是类似ArrayBlockingQueue那样的数组。但实际
使⽤过程中,不需要关⼼它的内部实现,如果指定了LinkedBlockingQueue的容量⼤⼩,那么它反映出来的使⽤特性就和ArrayBlockingQueue类似了。
LinkedBlockingQueue<Object> linkedQueue = new LinkedBlockingQueue<Object>(2);
linkedQueue.put(new Object());
班组安全活动// 插⼊第⼆个对象
linkedQueue.put(new Object());
// 插⼊第三个对象时,这个操作线程就会被阻塞。
落日余晖linkedQueue.put(new Object());
=======================================
// 或者如下使⽤:
LinkedBlockingQueue<Object> linkedQueue = new LinkedBlockingQueue<Object>();
linkedQueue.put(new Object());
// 插⼊第⼆个对象
linkedQueue.put(new Object());
// 插⼊第N个对象时,都不会阻塞
linkedQueue.put(new Object());
● LinkedBlockingDeque
LinkedBlockingDeque是⼀个基于链表的双端队列。LinkedBlockingQueue的内部结构决定了它只能从队列尾部插⼊,从队列头部取出元素;但是LinkedBlockingDeque既可以从尾部插⼊/取出元素,还可以从头部插⼊元素/取出元素。
LinkedBlockingDeque<TempObject> linkedDeque = new LinkedBlockingDeque<TempObject>();
// push,可以从队列的头部插⼊元素
linkedDeque.push(new TempObject(1));
linkedDeque.push(new TempObject(2));
linkedDeque.push(new TempObject(3));
// poll ,可以从队列的头部取出元素
TempObject tempObject = linkedDeque.poll();
// 这⾥会打印 tempObject.index = 3柳色
System.out.println("tempObject.index = " + Index());
// put ,可以从队列的尾部插⼊元素
linkedDeque.put(new TempObject(4));
linkedDeque.put(new TempObject(5));
// pollLast , 可以从队列尾部取出元素
tempObject = linkedDeque.pollLast();
// 这⾥会打印 tempObject.index = 5
System.out.println("tempObject.index = " + Index());
● PriorityBlockingQueue
PriorityBlockingQueue是⼀个按照优先级进⾏内部元素排序的⽆限队列。存放在PriorityBlockingQueue中的元素必须实现Comparable 接⼝,这样才能通过实现compareTo()⽅法进⾏排序。优先级最⾼的元素将始终排在队列的头部;PriorityBlockingQueue不会保证优先级⼀样的元素的排序,也不保证当前队列中除了优先级最⾼的元素以外的元素,随时处于正确排序的位置。
这是什么意思呢?PriorityBlockingQueue并不保证除了队列头部以外的元素排序⼀定是正确的。请看下⾯的⽰例代码:
PriorityBlockingQueue<TempObject> priorityQueue = new PriorityBlockingQueue<TempObject>();
priorityQueue.put(new TempObject(-5));
priorityQueue.put(new TempObject(5));
priorityQueue.put(new TempObject(-1));
priorityQueue.put(new TempObject(1));
// 第⼀个元素是5
// 实际上在还没有执⾏priorityQueue.poll()语句的时候,队列中的第⼆个元素不⼀定是1
TempObject targetTempObject = priorityQueue.poll();
System.out.println("tempObject.index = " + Index());
// 第⼆个元素是1
targetTempObject = priorityQueue.poll();
System.out.println("tempObject.index = " + Index());
// 第三个元素是-1
targetTempObject = priorityQueue.poll();
System.out.println("tempObject.index = " + Index());
// 第四个元素是-5
targetTempObject = priorityQueue.poll();
System.out.println("tempObject.index = " + Index());
// 这个元素类,必须实现Comparable接⼝
private static class TempObject implements Comparable<TempObject> {
private int index;
public TempObject(int index) {
this.index = index;
}
/**
* @return the index
*/
public int getIndex() {
return index;
}
/* (non-Javadoc)
* @e java.lang.Comparable#compareTo(java.lang.Object)
*/2005年属什么
@Override
public int compareTo(TempObject o) {
Index() - this.index;
}
}
● LinkedTransferQueue
LinkedTransferQueue也是⼀个⽆限队列,它除了具有⼀般队列的操作特性外(先进先出),还具有⼀个阻塞特性:LinkedTransferQueue可以由⼀对⽣产者/消费者线程进⾏操作,当消费者将⼀个新的元素插⼊队列后,消费者线程将会⼀直等待,直到某⼀个消费者线程将这个元素取⾛,反之亦然。
LinkedTransferQueue的操作特性可以由下⾯这段代码提现。在下⾯的代码⽚段中,有两中类型的线程:⽣产者和消费者,这两类线程互相等待对⽅的操作:
/**
* ⽣产者线程
*/
private static class ProducerRunnable implements Runnable {
private LinkedTransferQueue<TempObject> linkedQueue;
public ProducerRunnable(LinkedTransferQueue<TempObject> linkedQueue) {
this.linkedQueue = linkedQueue;
}
@Override
public void run() {
for(int index = 1 ; ; index++) {
try {
// 向LinkedTransferQueue队列插⼊⼀个新的元素
样的歌词// 然后⽣产者线程就会等待,直到有⼀个消费者将这个元素从队列中取⾛
ansfer(new TempObject(index));
} catch (InterruptedException e) {
e.printStackTrace(System.out);
}
}
}
}
/**
* 消费者线程
秋天的村庄*/
private static class ConsumerRunnable implements Runnable {
private LinkedTransferQueue<TempObject> linkedQueue;
public ConsumerRunnable(LinkedTransferQueue<TempObject> linkedQueue) {
this.linkedQueue = linkedQueue;
}
@Override
public void run() {
Thread currentThread = Thread.currentThread();
while(!currentThread.isInterrupted()) {
try {
重音记号// 等待,直到从LinkedTransferQueue队列中得到⼀个元素
TempObject targetObject = this.linkedQueue.take();
System.out.println("线程(" + Id() + ")取得targetObject.index = " + Index());
} catch (InterruptedException e) {
e.printStackTrace(System.out);
}
}
}
}
=====以下是启动代码:

本文发布于:2023-05-26 13:32:42,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/933034.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:队列   元素   线程   操作
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图