如何制作一个保留 FIFO 行为的 Java PriorityBlockingQueue?
我正在尝试在 Java 中创建一个优先级阻塞队列,以维护具有相同优先级的元素的 FIFO 顺序。 Oracle 文档对此提供了一些帮助,但我仍然很困惑。
我应该指出,以下主题对我来说都是非常新的:泛型、接口作为类型和静态嵌套类。所有这些都在下面的类定义中发挥作用。泛型尤其令人困惑,我确信我在这里完全搞砸了它们。
我已添加注释来识别我当前遇到的编译器错误。
几个具体问题:
可以让类代表排队事件对象,而实际队列是静态类成员吗?
将 Oracle 的 FIFO 事件“包装器”作为静态嵌套类包含在内是否合理?
我是否至少在正确的轨道上,在一个外部类中完成这一切?
这是我写的课程:
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
public class FIFOPBQEvent {
/**
* First we define a static nested class which, when instantiated,
* encapsulates the "guts" of the event - a FIFOPBQEvent - along with
* a sequence number that assures FIFO behavior of events of like priority.
*
* The following is lifted ALMOST verbatim (I added "static" and some
* comments) from Oracle documentation on adding FIFO-ness to a Priority
* Blocking Queue:
* http://download.oracle.com/javase/6/docs/api/java/util/concurrent/PriorityBlockingQueue.html
* As the Oracle doc points out:
*
* "A static nested class interacts with the instance members of its outer
* class (and other classes) just like any other top-level class. In
* effect, a static nested class is behaviorally a top-level class that
* has been nested in another top-level class for packaging convenience."
*
*/
static class FIFOEntry<E extends Comparable<? super E>> implements
Comparable<FIFOEntry<E>> {
final static AtomicLong seq = new AtomicLong();
final long seqNum; // instance
final E entry;
public FIFOEntry(E entry) {
seqNum = seq.getAndIncrement();
this.entry = entry;
}
public E getEntry() {
return entry;
}
/** Here is implementation of Comparable */
public int compareTo(FIFOEntry<E> other) {
int res = entry.compareTo(other.entry);
if (res == 0 && other.entry != this.entry)
res = (seqNum < other.seqNum ? -1 : 1);
return res;
}
}
/**
* Now we declare a single (static) PBQ of FIFO entries into which
* PBQFIFOEvents will be added and removed.
*/
/** FLAGGED AS ERROR BY COMPILER */
// Bound mismatch: The type FIFOPBQEvent is not a valid substitute for the
// bounded parameter <E extends Comparable<? super E>> of the type
// FIFOPBQEvent.FIFOEntry<E>
private static PriorityBlockingQueue<FIFOEntry<FIFOPBQEvent>> theQueue =
PriorityBlockingQueue<FIFOEntry<FIFOPBQEvent>>();
/**
* And here are the "guts" of our event: the i.d. and state of the GUI widget
*/
private ConsoleObject obj = ConsoleObject.UNDEFINED_OBJ; // widget that was affected
private ObjectState state = ObjectState.UNDEFINED_STATE; // the widget's new state
/**
* Constructor specifying the class variables
*/
public FIFOPBQEvent(ConsoleObject theObj, ObjectState theState) {
obj = theObj;
state = theState;
}
/**
* Event queuing ("sending") and dequeuing ("receiving")
*/
public void sendEvent() {
/** FLAGGED AS ERROR BY COMPILER */
// The method put(FIFOPBQEvent.FIFOEntry<FIFOPBQEvent>) in the type
// PriorityBlockingQueue<FIFOPBQEvent.FIFOEntry<FIFOPBQEvent>> is not
// applicable for the arguments (FIFOPBQEvent)
theQueue.put(this);
}
public static FIFOPBQEvent receiveEvent() {
/** FLAGGED AS ERROR BY COMPILER */
// Type mismatch: cannot convert from FIFOPBQEvent.FIFOEntry<FIFOPBQEvent>
// to FIFOPBQEvent
FIFOPBQEvent event = theQueue.take();
return event;
}
/**
* ConsoleEvent accessors
*/
public ConsoleObject getObj() {
return this.obj;
}
public ObjectState getState() {
return this.state;
}
/**
* And for the first time, enums instead of public static final ints.
*/
public enum ConsoleObject {
UNDEFINED_OBJ,
RESERVED,
/** Console keys */
RESET,
DISPLAY_MAR,
SAVE,
INSERT,
RELEASE,
START,
SIE,
SCE,
/** Console toggle switches */
POWER,
PARITY_CHECK,
IO_CHECK,
OVERFLOW_CHECK,
SENSE_SWITCH_1,
SENSE_SWITCH_2,
SENSE_SWITCH_3,
SENSE_SWITCH_4
}
public enum ObjectState {
UNDEFINED_STATE,
/** Toggle switches */
OFF,
ON,
/** Console keys */
PRESSED,
}
}
I'm trying to create a Priority Blocking Queue in Java that maintains FIFO order for elements with the same priority. The Oracle doc provides some help with that, but I'm still very tangled up.
I should note that the following topics are all very new to me: Generics, Interfaces as Types, and static nested classes. All of these come into play in the following class definition. Generics, especially, are confusing, and I'm sure I've totally messed up with them here.
I have included comments to identify the compiler errors I am currently getting.
Several specific questions:
Is it okay to have the class represent the queued event object, with the actual queue being a static class member?
Was it reasonable to have included Oracle's FIFO event "wrapper" as a static nested class?
Am I at least on the right track here, doing it all in one outer class?
Here is the class that I've written:
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
public class FIFOPBQEvent {
/**
* First we define a static nested class which, when instantiated,
* encapsulates the "guts" of the event - a FIFOPBQEvent - along with
* a sequence number that assures FIFO behavior of events of like priority.
*
* The following is lifted ALMOST verbatim (I added "static" and some
* comments) from Oracle documentation on adding FIFO-ness to a Priority
* Blocking Queue:
* http://download.oracle.com/javase/6/docs/api/java/util/concurrent/PriorityBlockingQueue.html
* As the Oracle doc points out:
*
* "A static nested class interacts with the instance members of its outer
* class (and other classes) just like any other top-level class. In
* effect, a static nested class is behaviorally a top-level class that
* has been nested in another top-level class for packaging convenience."
*
*/
static class FIFOEntry<E extends Comparable<? super E>> implements
Comparable<FIFOEntry<E>> {
final static AtomicLong seq = new AtomicLong();
final long seqNum; // instance
final E entry;
public FIFOEntry(E entry) {
seqNum = seq.getAndIncrement();
this.entry = entry;
}
public E getEntry() {
return entry;
}
/** Here is implementation of Comparable */
public int compareTo(FIFOEntry<E> other) {
int res = entry.compareTo(other.entry);
if (res == 0 && other.entry != this.entry)
res = (seqNum < other.seqNum ? -1 : 1);
return res;
}
}
/**
* Now we declare a single (static) PBQ of FIFO entries into which
* PBQFIFOEvents will be added and removed.
*/
/** FLAGGED AS ERROR BY COMPILER */
// Bound mismatch: The type FIFOPBQEvent is not a valid substitute for the
// bounded parameter <E extends Comparable<? super E>> of the type
// FIFOPBQEvent.FIFOEntry<E>
private static PriorityBlockingQueue<FIFOEntry<FIFOPBQEvent>> theQueue =
PriorityBlockingQueue<FIFOEntry<FIFOPBQEvent>>();
/**
* And here are the "guts" of our event: the i.d. and state of the GUI widget
*/
private ConsoleObject obj = ConsoleObject.UNDEFINED_OBJ; // widget that was affected
private ObjectState state = ObjectState.UNDEFINED_STATE; // the widget's new state
/**
* Constructor specifying the class variables
*/
public FIFOPBQEvent(ConsoleObject theObj, ObjectState theState) {
obj = theObj;
state = theState;
}
/**
* Event queuing ("sending") and dequeuing ("receiving")
*/
public void sendEvent() {
/** FLAGGED AS ERROR BY COMPILER */
// The method put(FIFOPBQEvent.FIFOEntry<FIFOPBQEvent>) in the type
// PriorityBlockingQueue<FIFOPBQEvent.FIFOEntry<FIFOPBQEvent>> is not
// applicable for the arguments (FIFOPBQEvent)
theQueue.put(this);
}
public static FIFOPBQEvent receiveEvent() {
/** FLAGGED AS ERROR BY COMPILER */
// Type mismatch: cannot convert from FIFOPBQEvent.FIFOEntry<FIFOPBQEvent>
// to FIFOPBQEvent
FIFOPBQEvent event = theQueue.take();
return event;
}
/**
* ConsoleEvent accessors
*/
public ConsoleObject getObj() {
return this.obj;
}
public ObjectState getState() {
return this.state;
}
/**
* And for the first time, enums instead of public static final ints.
*/
public enum ConsoleObject {
UNDEFINED_OBJ,
RESERVED,
/** Console keys */
RESET,
DISPLAY_MAR,
SAVE,
INSERT,
RELEASE,
START,
SIE,
SCE,
/** Console toggle switches */
POWER,
PARITY_CHECK,
IO_CHECK,
OVERFLOW_CHECK,
SENSE_SWITCH_1,
SENSE_SWITCH_2,
SENSE_SWITCH_3,
SENSE_SWITCH_4
}
public enum ObjectState {
UNDEFINED_STATE,
/** Toggle switches */
OFF,
ON,
/** Console keys */
PRESSED,
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
第一个错误是更严重的错误。发生这种情况是因为
FIFOPBQEvent
类未实现Comparable
,它必须被视为FIFOEntry
嵌套类的泛型类型。这是因为您限制了E
并说它扩展了 Comparable<...>
。基本上,您的 FIFOPBQEvent 类必须具有可比性才能为队列提供优先级(大概基于事件类型)。要修复该错误,您需要:
将类的标头更改为:
在
FIFOPBQEvent
类中添加一个compareTo
方法;像这样:然后您需要将您的条目包装在
sendEvent
方法中:最后一个小错误只是您没有解开
FIFOEntry
对象。要解决此问题,请将receiveEvent
更改为:The first error is the more significant error. It occurs because the
FIFOPBQEvent
class doesn't implementComparable
, which it must to be considered as the generic type for theFIFOEntry
nested class. This is because you restrictE
and say that itextends Comparable<...>
. Basically, yourFIFOPBQEvent
class must be comparable to provide the priority for the queue (presumably based on the event type).To fix the error, you need to:
Change the header of your class to:
add a
compareTo
method in theFIFOPBQEvent
class; something like:Then you need to wrap your entry in your
sendEvent
method:The last, minor, error is simply that you aren't unwrapping the
FIFOEntry
object. To fix this, changereceiveEvent
to:让我们单步执行您的代码。
这定义了带有通用参数的
FIFOEntry
类。您已将泛型参数的类型限制为“任何实现自身 Comparable 的对象”。您对 PriorityBlockingQueue 的声明在这里并不不正确,但您对
FIFOEntry
的定义不正确。这是因为上述一点 - 您已将FIFOEntry
的类型限制为实现 Comparable 本身的任何类型,即它应该是您的下一个问题是 -
this
的类型是FIFOPBQEvent
但队列只接受FIFOEntry
对象。为了匹配您的队列签名,它应该是:您在
receiveEvent()
上也有同样的问题 - 您的队列签名表明队列包含 FIFOEntry 对象,并且您正在尝试提取 FIFOPBQEvents。Let's step through your code.
This defines the class
FIFOEntry
which takes a generic parameter. You have constrained the type of generic parameter to "Any object that implements Comparable of itself".Your declaration of PriorityBlockingQueue is not incorrect here, but your definition of
FIFOEntry<FIFOPBQEvent>
is incorrect. This is because of the above point - you have restricted the type ofFIFOEntry
to anything that implements Comparable of itself i.e. it should beYour next problem is -
The type of
this
isFIFOPBQEvent
but the queue only acceptsFIFOEntry
objects. To match your Queue signature it should be:You have the same problem on
receiveEvent()
too - your Queue signature says that the Queue contains FIFOEntry objects and you are trying to pull out FIFOPBQEvents.根据@101100的建议,我重新设计了设计,将队列与事件解耦。这似乎使它更简单、更容易理解(和重用),但遗憾的是我仍然不清楚一些概念。接下来是 PriorityFIFOEventQueue(为简洁起见,我省略了 Event 类)。我已经注意到我仍然需要一些帮助的地方:
以下标记有诊断:“类型 PriorityFIFOEventQueue 必须实现继承的抽象方法 Comparable>.compareTo (PriorityFIFOEventQueue)”
我很确定我不想比较 < em>队列!!仍然不确定我在这里需要什么。
在下面,包含“compareTo”的行被标记,并且诊断是
“对于类型 E 来说,compareTo(E) 方法未定义”。显然我还没有告诉编译器
“其他”FIFOEntry 实现了 Comparable。
Taking @101100's recommendation, I have reworked the design, decoupling the queue from the events. That seems to make it much simpler and easier to understand (and reuse), but sadly I'm still unclear on some concepts. What follows here is the PriorityFIFOEventQueue (I've omitted the Event class for brevity). And I've noted where I still need some help:
The following is flagged with diagnostic: "The type PriorityFIFOEventQueue must implement the inherited abstract method Comparable>.compareTo (PriorityFIFOEventQueue)"
I'm pretty sure I don't want to compare queues !! Still not sure what I need here.
In the following, the line containing "compareTo" is flagged, and the diagnostic is
"The method compareTo(E) is undefined for the type E". Apparently I haven't told the compiler
that the "other" FIFOEntry implements Comparable.
这是 PriorityBlockingQueue 的实际替代品,它维护具有相同优先级的项目的 FIFO 排序。它为用户透明地完成所有包装/展开。
此代码是为 1.4 JVM 编写的,并使用 juc 向后移植。在较新的 JVM 中使用它并添加泛型应该很简单。
Here is an actual replacement for PriorityBlockingQueue which maintains FIFO ordering for items with equal priority. It does all the wrapping/unwrapping transparently for the user.
This code was written for a 1.4 JVM and usese the j.u.c. backport. Using it in a newer JVM and adding generics should be straightforward.