zl程序教程

您现在的位置是:首页 >  后端

当前栏目

并发集合(四)用优先级对使用阻塞线程安全的列表排序

2023-09-14 08:56:51 时间

用优先级对使用阻塞线程安全的列表排序

一个典型的需求是,当你需要使用一个有序列表的数据结构时,Java提供的PriorityBlockingQueue类就拥有这种功能。

你想要添加到PriorityBlockingQueue中的所有元素必须实现Comparable接口。这个接口有一个compareTo()方法,它接收同样类型的对象,你有两个比较的对象:一个是执行这个方法的对象,另一个是作为参数接收的对象。如果本地对象小于参数,则该方法返回小于0的数值。如果本地对象大于参数,则该方法返回大于0的数值。如果本地对象等于参数,则该方法返回等于0的数值。

PriorityBlockingQueue使用compareTo()方法决定插入元素的位置。(校注:默认情况下)较大的元素将被放在队列的尾部。

阻塞数据结构(blocking data structure)是PriorityBlockingQueue的另一个重要特性。它有这样的方法,如果它们不能立即进行它们的操作,则阻塞这个线程直到它们的操作可以进行。

在这个指南中,你将学习如何使用PriorityBlockingQueue类实现一个例子,你将在相同的列表上使用不同的优先级存储大量事件(event),然后检查队列的排序是否是你想要的。

准备工作…

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.实现Event类,并指定它实现参数化为Event类的Comparable接口。


7.实现compareTo()方法。它接收Event作为参数,并且比较当前事件与参数的优先级。如果当前事件的优先级更大,则返回-1,如果这两个优先级相等,则返回0,如果当前事件的优先级更小,则返回1。注意,这与大多数Comparator.compareTo()的实现是相反的。


10.声明一个私有的、参数化为Event类的PriorityBlockingQueue类型的属性queue,用来存储任务产生的事件。


12.实现run()方法。它存储100个事件到队列,使用它们的ID来标识创建事件的任务,并给予不断增加的数作为优先级。使用add()方法添加事件到队列中。


19.将列队真实大小和存储在它里面的事件写入到控制台。使用poll()方法从队列中取出事件。


它是如何工作的…

在这个指南中,你已使用PriorityBlockingQueue实现Event对象的一个优先级队列。正如我们在引言中提到的,所有存储在PriorityBlockingQueue的元素必须实现Comparable接口,所以,你已在Event类中实现compareTo()方法。

所有事件都有一个优先级属性。拥有更高优先级的元素将成为队列的第一个元素。当你已实现compareTo()方法,如果执行这个方法的事件拥有比作为参数传入的事件更高的优先级时,它将返回-1。在其他情况下,如果执行这个方法的事件拥有比作为参数传入的事件更低的优先级时,它将返回1。如果这两个对象拥有相同优先级,compareTo()方法将返回0。在这种情况下,PriorityBlockingQueue类并不能保证元素的顺序。

我们已实现Task类来添加Event对象到优先级队列中。每个任务对象使用add()方法往队列添加1000个事件(0到99种优先级)。

Main类的main()方法创建5个Task对象,并用相应的线程执行它们。当所有的线程完成它们的执行,你已将所有元素写入到控制台。我们使用poll()方法从队列中获取元素。这个方法返回并删除队列的第一个元素。

以下截图显示执行这个程序的部分输出:

2

你可以看出这个队列如何有5000个元素,第一个元素如何拥有最大的优先级值。

不止这些…

PriorityBlockingQueue类提供其他有趣的方法,以下是其中一些方法的描述:

clear():这个方法删除队列中的所有元素。 take():这个方法返回并删除队列中的第一个元素。如果队列是空的,这个方法将阻塞线程直到队列有元素。 put(E e):E是用来参数化PriorityBlockingQueue类的类。这个方法将作为参数传入的元素插入到队列中。 peek():这个方法返回列队的第一个元素,但不删除它。
让线程按顺序执行8种方法 本文使用了7中方法实现在多线程中让线程按顺序运行的方法,涉及到多线程中许多常用的方法,不止为了知道如何让线程按顺序运行,更是让读者对多线程的使用有更深刻的了解。 使用的方法如下:
为什么 HashMap 并发时会引起死循环? 今天研读Java并发容器和框架时,看到为什么要使用ConcurrentHashMap时,其中有一个原因是:线程不安全的HashMap, HashMap在并发执行put操作时会引起死循环,是因为多线程会导致HashMap的Entry链表形成环形数据结构,查找时会陷入死循环。
有的时候我们希望线程按照希望的顺序依次执行,比如线程A,B,C,按照顺序依次执行,这时候就要用到阻塞和唤醒,之前的时候我们学到过wait()和nofity/notifyAll()这两个方法,这里我们使用java.
最近看了这位博主的文章 写的挺好的 跟着里面的线程 温习了一遍 结尾处有道题算是复习巩固吧 我是用ReentrantLock实现的 而不是synchronized
ali清英 方腾飞,花名清英,英文名kiral,并发编程网创始人,支付宝技术专家,《Java并发编程的艺术》作者。