介绍:
基于优先级堆的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator
进行排序,具体取决于所使用的构造方法。
优先级队列不允许使用 null
元素。
依靠自然顺序的优先级队列还不允许插入不可比较的对象。
此队列的头 是按指定排序方式确定的最小 元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。
优先级队列是无界的,但是有一个内部容量控制着用于存储队列元素的数组大小,它通常至少等于队列的大小。
随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。
虽然此队列逻辑上是无界的,但是资源被耗尽时试图执行 add 操作也将失败。
1、PriorityQueue
非同步队列。
在多线程同时读写时会出现异常。
2、PriorityBlockingQueue
同步队列。
适用于多线程环境中。
3、实现方式:
PriorityQueue部分是测试PriorityQueue用,因为在多线程时有同步问题,可能在开发中不适用。
①队列中元素用 Comparator
进行排序
要自己实现Comparator
接口类。添加进优先队列中的数据,Queue会调用Comparator进行比较,小的数据会放在Queue的前部,反之,放在后部。最小的数据会放在Queue的头部。(具体实现?)
放在Queue中的数据只有添加时才进行比较,加入后的位置是不会改变的——所以元素比较用的值最好是固定的,否则取出的数据有可能不是最优先的。
Comparators实现代码:
Comparator实现类
import java.util.Comparator;
public class Comparators implements Comparator<Executor> {
@Override
public int compare(Executor paramT1, Executor paramT2) {
return (int)(paramT1.getDeadline() - paramT2.getDeadline());
}
}
Executor实现代码:
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;
public class Executor implements Runnable{
private long createTime;
private long timeout;
private OutputStreamWriter writer;
public Executor(long timeout, OutputStreamWriter writer){
this.timeout = timeout;
createTime = new Date().getTime();
this.writer = writer;
}
@Override
public void run() {
try {
writer.write("createTime>>[" + createTime + "] timeout>>[" + timeout + "] hashcode>>[" + (createTime + timeout) + "]\r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
public long getDeadline(){
return this.createTime + this.timeout;
}
}
写入文件的原因是多线程写入会保证写入的顺序,基本可以保证取得的数据的顺序是Queue中的顺序。
测试代码
class Consumer implements Runnable {
private AtomicInteger counter;
private PriorityBlockingQueue<Executor> runQueue;
public Consumer(PriorityBlockingQueue<Executor> runQueue, AtomicInteger counter){
// private PriorityQueue<Executor> runQueue;
// public Consumer(PriorityQueue<Executor> runQueue, AtomicInteger counter){
this.runQueue = runQueue;
this.counter = counter;
}
@Override
public void run() {
Executor exe = null;
while((exe = runQueue.poll()) != null){
exe.run();
counter.decrementAndGet();
}
}
}
class Producer implements Runnable {
private AtomicInteger counter;
private OutputStreamWriter writer;
private PriorityBlockingQueue<Executor> runQueue;
public Producer(PriorityBlockingQueue<Executor> runQueue, AtomicInteger counter,
OutputStreamWriter writer){
// private PriorityQueue<Executor> runQueue;
// public Producer(PriorityQueue<Executor> runQueue, AtomicInteger counter,
// OutputStreamWriter writer){
this.runQueue = runQueue;
this.counter = counter;
this.writer = writer;
}
@Override
public void run() {
Random rand = new Random();
for(int i=0; i < 1000; i++){
long timeout = rand.nextInt(10000000);
Executor exe = new Executor(timeout, writer);
runQueue.offer(exe);
counter.incrementAndGet();
}
}
}
//测试函数代码
public static void TestWithComparator() throws InterruptedException, IOException{
AtomicInteger counter = new AtomicInteger();
// PriorityQueue<Executor> runQueue = new PriorityQueue<Executor>(1000);
PriorityBlockingQueue<Executor> runQueue = new PriorityBlockingQueue<Executor>(1000, new Comparators());
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("e:\\priorityQueue.txt"));
ExecutorService producerPool = Executors.newFixedThreadPool(16);
long start = System.nanoTime();
for(int i=0; i < 1000; i++){
producerPool.execute(new Producer(runQueue, counter, writer));
}
producerPool.shutdown();
while(!producerPool.isTerminated()){
}
long end = System.nanoTime();
System.out.println("comparator add time is " + (end - start));
ExecutorService consumerPool = Executors.newFixedThreadPool(16);
start = System.nanoTime();
for(int i=0; i < 16; i++){
consumerPool.execute(new Consumer(runQueue, counter));
}
consumerPool.shutdown();
while(!consumerPool.isTerminated()){
;
}
end = System.nanoTime();
System.out.println("comparator exe time is " + (end - start));
System.out.println(counter.get());
writer.close();
}
②队列中元素实现Comparable接口进行排序
添加入队列中的元素要实现Comparable接口,排序时调用实现Comparable接口的compareTo方法进行比较,排序的结果同①。
ExecutorCmp
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;
public class ExecutorCmp implements Runnable, Comparable<ExecutorCmp>{
private long createTime;
private long timeout;
private OutputStreamWriter writer;
public ExecutorCmp(long timeout, OutputStreamWriter writer){
this.timeout = timeout;
createTime = new Date().getTime();
this.writer = writer;
}
@Override
public void run() {
try {
writer.write("createTime>>[" + createTime + "] timeout>>[" + timeout + "] hashcode>>[" + (createTime + timeout) + "]\r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public int compareTo(ExecutorCmp arg0) {
return (int)((this.createTime + this.timeout) - (arg0.createTime + arg0.timeout));
}
}
Comparable测试代码
class CmpConsumer implements Runnable {
private AtomicInteger counter;
private PriorityBlockingQueue<ExecutorCmp> runQueue;
public CmpConsumer(PriorityBlockingQueue<ExecutorCmp> runQueue, AtomicInteger counter){
// private PriorityQueue<Executor> runQueue;
// public Consumer(PriorityQueue<Executor> runQueue, AtomicInteger counter){
this.runQueue = runQueue;
this.counter = counter;
}
@Override
public void run() {
ExecutorCmp exe = null;
while((exe = runQueue.poll()) != null){
exe.run();
counter.decrementAndGet();
}
}
}
class CmpProducer implements Runnable {
private AtomicInteger counter;
private OutputStreamWriter writer;
private PriorityBlockingQueue<ExecutorCmp> runQueue;
public CmpProducer(PriorityBlockingQueue<ExecutorCmp> runQueue, AtomicInteger counter,
OutputStreamWriter writer){
// private PriorityQueue<Executor> runQueue;
// public Producer(PriorityQueue<Executor> runQueue, AtomicInteger counter,
// OutputStreamWriter writer){
this.runQueue = runQueue;
this.counter = counter;
this.writer = writer;
}
@Override
public void run() {
Random rand = new Random();
for(int i=0; i < 1000; i++){
long timeout = rand.nextInt(10000000);
ExecutorCmp exe = new ExecutorCmp(timeout, writer);
runQueue.offer(exe);
counter.incrementAndGet();
}
}
}
//测试函数代码:
public static void testWithComparable() throws InterruptedException, IOException{
AtomicInteger counter = new AtomicInteger();
PriorityBlockingQueue<ExecutorCmp> runQueue = new PriorityBlockingQueue<ExecutorCmp>(1000);
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("e:\\priorityQueue1.txt"));
ExecutorService producerPool = Executors.newFixedThreadPool(16);
long start = System.nanoTime();
for(int i=0; i < 1000; i++){
producerPool.execute(new CmpProducer(runQueue, counter, writer));
}
producerPool.shutdown();
while(!producerPool.isTerminated()){
}
long end = System.nanoTime();
System.out.println("comparatable add time is " + (end - start));
ExecutorService consumerPool = Executors.newFixedThreadPool(16);
start = System.nanoTime();
for(int i=0; i < 16; i++){
consumerPool.execute(new CmpConsumer(runQueue, counter));
}
consumerPool.shutdown();
while(!consumerPool.isTerminated()){
;
}
end = System.nanoTime();
System.out.println("comparatable exe time is " + (end - start));
System.out.println(counter.get());
writer.close();
}
4、在ThreadPoolExecutor中的应用方式
PriorityBlockingQueue保存这些Runnable,必须对Runnable进行封装,并实现Comparable接口。
代码如下:
class SafTask implements Runnable, Comparable<SafTask> {
private int order;
public SafTask(int order){
this.order = order;
}
public void run() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(order);
}
@Override
public int compareTo(SafTask other) {
return this.order - other.order;
}
}
//测试代码
BlockingQueue<Runnable> configQueue = new PriorityBlockingQueue<Runnable>();
ThreadPoolExecutor stpe = new ThreadPoolExecutor(1, 10, 1000, TimeUnit.MILLISECONDS, configQueue);
Random rand = new Random();
for(int i = 0; i < 1000; i++){
int order = rand.nextInt(1000);
Thread.sleep(3);
stpe.execute(new SafTask(order));
}
stpe.shutdown();
结论:
1、使用PriorityBlockingQueue时元素实现Comparable接口进行排序性能上会高一些:
comparator add time is 250168728
comparator exe time is 2755292150
*********************************************************************************
comparatable add time is 218674112
comparatable exe time is 2222345324
2、在ThreadPoolExecutor中使用PriorityBlockingQueue时,要封装Runnable并实现Comparable接口