2011-07-08 33 views
7

我試圖在Java中創建一個優先級阻止隊列,該優先級阻止隊列爲具有相同優先級的元素保持FIFO順序。 Oracle文檔提供了一些幫助,但我仍然很糾結。如何創建保留FIFO行爲的Java PriorityBlockingQueue?

我應該注意的是,以下主題都非常新的對我說:泛型接口,類型,並靜態嵌套類。所有這些都在下面的類定義中起作用。泛型,尤其是混淆,我相信我在這裏完全搞砸了他們。

我已經包含了評論來識別我目前正在收到的編譯器錯誤。

幾個具體的問題:

  1. 是不是好有類代表排隊的事件對象,與實際隊列爲類的靜態成員?

  2. 將Oracle的FIFO事件「包裝器」包含爲靜態嵌套類是否合理?

  3. 我是否至少在正確的軌道上,在一個外部課堂上做這一切?

這裏是我寫的類:通過您的代碼

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, 
} 
} 
+0

'FIFOPBQEvent'沒有實現'可比'這會導致一些你的錯誤那裏。您的FIFOEntry的通用聲明需要實現Comparable接口的對象。 – Bringer128

回答

4

第一個錯誤是更重要的錯誤。這是因爲FIFOPBQEvent類沒有實現Comparable,因此它必須被視爲嵌套類的通用類型。這是因爲你限制了E並且說它是extends Comparable<...>。基本上,您的類必須可以提供隊列的優先級(可能基於事件類型)。

要修正此錯誤,您需要:

  1. 改變你的類的頭:

    public class FIFOPBQEvent implements Comparable<FIFOPBQEvent> { 
    
  2. 添加在FIFOPBQEventcompareTo方法;是這樣的:

    public int compareTo (FIFOPBQEvent other) { 
        // TODO - compare this and other for priority 
        return 0; 
    } 
    

然後你需要用你進入你的sendEvent方法:

public void sendEvent() { 
    theQueue.put(new FIFOEntry<FIFOPBQEvent> (this)); 
} 

最後,未成年人,錯誤很簡單,你是不是展開了FIFOEntry對象。爲了解決這個問題,改變receiveEvent到:

public static FIFOPBQEvent receiveEvent() { 
    FIFOPBQEvent event = theQueue.take().getEntry(); 
    return event; 
} 
+0

謝謝你 - 我做了你提到的變化,只有一個剩餘的語句被標記: ' 私人靜態的PriorityBlockingQueue > theQueue = 的PriorityBlockingQueue >(); ' 編譯器診斷需要()s之間的表達式。不知道爲什麼,因爲PriorityBlockingQueue文檔默認的構造函數。 – Chap

+1

啊,你忘了'新'。 – 101100

2

讓我們一步。

static class FIFOEntry<E extends Comparable<? super E>> implements 
    Comparable<FIFOEntry<E>> { 

這定義了類別FIFOEntry,它採用一個通用參數。您已將通用參數的類型限制爲「實現自身Comparable的任何對象」。

private static PriorityBlockingQueue<FIFOEntry<FIFOPBQEvent>> theQueue = 
    PriorityBlockingQueue<FIFOEntry<FIFOPBQEvent>>(); 

你的PriorityBlockingQueue的聲明不是不正確這裏,但你的FIFOEntry<FIFOPBQEvent>定義不正確。這是因爲上述點 - 你有限制的FIFOEntry類型任何實現可比本身即它應該是

class FIFOPBQEvent implements Comparable<FIFOPBQEvent> { 

你的下一個問題是 -

public void sendEvent() { 
    theQueue.put(this); 
} 

類型的thisFIFOPBQEvent但該隊列只接受FIFOEntry對象。爲了配合您的隊列簽名應該是:

public void sendEvent() { 
    // Requires FIFOPBQEvent to be Comparable 
    theQueue.put(new FIFOEntry<FIFOPBQEvent>(this));  
} 

您對receiveEvent()同樣的問題太多 - 你的隊列的簽名說,該隊列包含FIFOEntry對象和你正在試圖拔出FIFOPBQEvents。

+0

沒有糊塗我的答案,泛型類型>匹配「實現Comparable自身或超類的任何對象」。也就是說,'類Cat實現可比較的'匹配這個簽名,就像'class Cat implements Comparable ' – Bringer128

+0

我非常感謝你在這裏的幫助。爲什麼類都擴展**和**實現**界面** Comparable **?我以爲只有一個_implemented_接口。 – Chap

+0

一個想法:如果我使用FIFOEntry作爲外部類,這可能會更容易理解,讓_that_包含靜態PBQ,並使FIFOPBQEntry成爲靜態嵌套(或內部?)?至少可以恰當地反映FIFOEntry和PBQEntry之間的實際遏制關係。事實上,這種感覺有點內向外。 – Chap

1

以@ 101100的建議,我已經修改了設計,解耦從事件隊列中。這似乎使它更簡單,更容易理解(和重用),但遺憾的是我仍然不清楚一些概念。以下是PriorityFIFOEventQueue(爲簡潔起見,我省略了Event類)。而且我注意到,我還需要一些幫助:

package ibm1620; 

import java.util.concurrent.PriorityBlockingQueue; 
import java.util.concurrent.atomic.AtomicLong; 

/** 
* This class represents a Priority Blocking Queue of FIFO entries. Instantiating 
* it creates a queue. It provides instance methods for sending and receiving 
* entries, a.k.a. events of type E, on the queue. 
*/ 

與診斷標記如下:「類型PriorityFIFOEventQueue必須實現繼承的抽象方法可比> .compareTo(PriorityFIFOEventQueue)」

我米很確定我不想比較隊列!仍然不確定我需要什麼。

public class PriorityFIFOEventQueue<E extends Comparable<? super E>> implements Comparable<PriorityFIFOEventQueue<E>> { 

/** 
* FIFOEntry is a static nested class that wraps an Entry and provides support for 
* keeping the Entries in FIFO sequence. 
*/ 
private static class FIFOEntry<E> implements Comparable<FIFOEntry<E>> { 

    /** 
    * There's going to be one atomic seq per ... queue? runtime? 
    */ 

    final static AtomicLong seq = new AtomicLong(); 

    /** 
    * FIFOEntry is simply an entry of type E, and a sequence number 
    */ 
    final long seqNum; 
    final E entry; 

    /** 
    * FIFOEntry() constructor 
    */ 
    FIFOEntry(E entry) { 
     seqNum = seq.getAndIncrement(); 
     this.entry = entry; 
    } 

    /** 
    * Accessor method for entry 
    */ 
    E getEntry() { 
     return entry; 
    } 

    /** 
    * Here is implementation of Comparable that is called directly by PBQ. 
    * We first invoke E's comparator which compares based on priority. 
    * If equal priority, order by sequence number (i.e. maintain FIFO). 
    * */ 

在下文中,含有「的compareTo」行被標記,並且診斷是 「的方法的compareTo(E)是未定義的類型E」。顯然我沒有告訴編譯器 「其他」FIFOEntry實現了Comparable。

public int compareTo(FIFOEntry<E> other) { 
     int res = entry.compareTo(other.entry); // priority-based compare 
     if (res == 0 && other.entry != this.entry) 
      res = (seqNum < other.seqNum ? -1 : 1); // FIFO compare 
     return res; 
    } 
} 

/** 
* Here is the PriorityBlockingQueue of FIFOEntries 
*/ 

private PriorityBlockingQueue<FIFOEntry<E>> theQueue = 
    new PriorityBlockingQueue<FIFOEntry<E>>(); 

/** 
* Event queuing ("sending") and dequeuing ("receiving") 
*/ 
public void sendEvent(E event) { 
    theQueue.put(new FIFOEntry<E>(event)); 
} 

/** 
* pollEvent() 
* Will remove and return a ConsoleEvent from the queue, or return 
* null if queue is empty. 
*/ 
public E pollEvent() { 
    E event = null; 
    FIFOEntry<E> aFIFOEvent = theQueue.poll(); 
    if (aFIFOEvent != null) { 
     event = aFIFOEvent.getEntry(); 
     say("pollEvent() -> "+event); 
    } 
    else { 
    } 
    return event; 
} 

/** 
* receiveEvent() 
* Will block if queue is empty. Takes a FIFOEvent off the queue, 
* unwraps it and returns the 'E' payload. 
* 
* @return 
*/ 
public E receiveEvent() { 
    E event = null; 
    try { 
     FIFOEntry<E> aFIFOEvent = theQueue.take(); 
     if (aFIFOEvent != null) { 
      event = aFIFOEvent.getEntry(); 
      say("receiveEvent() -> "+event); 
     } 

    } catch (InterruptedException e) { 
     say("InterruptedException in receiveEvent()"); 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return event; 
} 

// for console debugging 
static void say(String s) { 
    System.out.println("ConsoleEvent: " + s); 
} 

} 
+0

好吧 - 在我停止敲打我的頭後,我意識到FIFOEvent的類定義應該是:** private static class FIFOEntry > implements comparable > {'**。 (Duh - 正如Oracle文檔所描述的!)然而,仍然不確定PriorityFIFOEventQueue的定義。 – Chap

+1

爲了理解'Comparable'和其他接口,我覺得將它看作描述符是很有幫助的,就像易燃。所以你應該能夠合理地說任何實現類的類都是可比的。現在,你說'FIFOEntry'具有可比性,這是有道理的。你也在說'PriorityFIFOEventQueue'具有可比性,這對我來說沒有意義;你爲什麼要比較它們? – 101100

+0

@ 101100 - 你說得對,我不想比較隊列,所以我刪除了「implements」子句。但我想比較「E's」 - 這讓我覺得我應該寫**公共類PriorityFIFOEventQueue > **。 (對我來說,談論「擴展」一個接口看起來很奇怪,但編譯器似乎並不介意。)@ Bringer128試圖向我解釋** **部分,但我不確定我需要它,要麼。這目前編譯和運行正確,雖然我當然需要審查有限的類型參數之前,我很舒服。 – Chap

1

以下是PriorityBlockingQueue的實際替代方案,該方法爲優先級相同的項目維護FIFO排序。它爲用戶透明地進行所有的打包/解包。

此代碼是爲1.4 JVM編寫的,並使用j.u.c.反向移植。在較新的JVM中使用它並添加泛型應該很簡單。

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.Comparator; 
import java.util.ConcurrentModificationException; 
import java.util.Iterator; 
import java.util.NoSuchElementException; 

import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue; 
import edu.emory.mathcs.backport.java.util.concurrent.PriorityBlockingQueue; 
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; 
import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicLong; 

/** 
* A queue with all properties of a {@link PriorityBlockingQueue} but which additionally 
* returns items with equal priority 
* in a FIFO order. 
* In this respect, {@link PriorityBlockingQueue} explicitly gives no return order guarantees for equal priority elements. 
* 
* This queue only accepts {@link Comparable} items. A custom {@link Comparator} cannot 
* be specified at construction time. 
* 
* 
*/ 
public final class FIFOPriorityBlockingQueue implements BlockingQueue { 
    private final PriorityBlockingQueue q; 

    public FIFOPriorityBlockingQueue() { 
     q = new PriorityBlockingQueue(); 
    } 

    public FIFOPriorityBlockingQueue(int initialCapacity) { 
     q = new PriorityBlockingQueue(initialCapacity); 
    } 

    public boolean isEmpty() { 
     return q.isEmpty(); 
    } 

    public boolean addAll(Collection c) { 
    if (c == null) 
     throw new NullPointerException(); 
    if (c == this) 
     throw new IllegalArgumentException(); 
    boolean modified = false; 
    Iterator e = c.iterator(); 
    while (e.hasNext()) { 
     if (add(e.next())) 
     modified = true; 
    } 
    return modified; 
    } 

    /** 
    * Always returns <code>null</code> as this {@link BlockingQueue} only accepts 
    * {@link Comparable} objects and doesn't allow setting an own {@link Comparator} 
    * @return 
    */ 
    public Comparator comparator() { 
     return null; 
    } 

    public boolean containsAll(Collection c) { 
     Iterator e = c.iterator(); 
     while (e.hasNext()) 
      if(!contains(e.next())) 
      return false; 

     return true; 
    } 

    public int size() { 
     return q.size(); 
    } 

    public int remainingCapacity() { 
     return q.remainingCapacity(); 
    } 

    public boolean removeAll(Collection c) { 
     boolean modified = false; 
     Iterator e = iterator(); 
     while (e.hasNext()) { 
      if(c.contains(e.next())) { 
      e.remove(); 
      modified = true; 
      } 
     } 
     return modified; 
    } 

    public boolean retainAll(Collection c) { 
     boolean modified = false; 
     Iterator e = iterator(); 
     while (e.hasNext()) { 
      if(!c.contains(e.next())) { 
      e.remove(); 
      modified = true; 
      } 
     } 
     return modified; 
    } 

    public Object remove() { 
     return ((FIFOEntry)q.remove()).entry; 
    } 

    public Object element() { 
     return ((FIFOEntry)q.element()).entry; 
    } 

    public boolean add(Object e) { 
     return q.add(new FIFOEntry((Comparable)e)); 
    } 

    public boolean offer(Object e) { 
     return q.offer(new FIFOEntry((Comparable)e)); 
    } 

    public void put(Object e) { 
     q.put(new FIFOEntry((Comparable)e)); 
    } 

    public boolean offer(Object e, long timeout, TimeUnit unit) { 
     return q.offer(new FIFOEntry((Comparable)e), timeout, unit); 
    } 

    public Object poll() { 
     return ((FIFOEntry)q.poll()).entry; 
    } 

    public Object take() throws InterruptedException { 
     return ((FIFOEntry)q.take()).entry; 
    } 

    public Object poll(long timeout, TimeUnit unit) throws InterruptedException { 
     return ((FIFOEntry)q.poll(timeout, unit)).entry; 
    } 

    public Object peek() { 
     return ((FIFOEntry)q.peek()).entry; 
    } 

    /** 
    * If more than one equal objects are held by the queue, remove() will 
    * remove any one of them, not necessarily the first or last inserted. 
    */ 
    public boolean remove(Object o) { 
     return q.remove(new FIFOEntry((Comparable)o)); 
    } 

    public boolean contains(Object o) { 
     return q.contains(new FIFOEntry((Comparable)o)); 
    } 

    public Object[] toArray() { 
     Object[] a = q.toArray(); 
     for (int i = 0; i < a.length; i++) { // unpacking 
      a[i] = ((FIFOEntry)a[i]).entry; 
     } 
     return a; 
    } 

    public String toString() { 
     return q.toString(); // ok, because each FIFOEntry.toString returns the toString of the entry 
    } 

    public int drainTo(Collection c) { 
     ArrayList tmp = new ArrayList(size()); 
     int n = q.drainTo(tmp); 
     for (Iterator it = tmp.iterator(); it.hasNext();) { 
      FIFOEntry en = (FIFOEntry) it.next(); 
      c.add(en.entry); 
     } 
     return n; 
    } 



    public int drainTo(Collection c, int maxElements) { 
     ArrayList tmp = new ArrayList(size()); 
     int n = q.drainTo(tmp, maxElements); 
     for (Iterator it = tmp.iterator(); it.hasNext();) { 
      FIFOEntry en = (FIFOEntry) it.next(); 
      c.add(en.entry); 
     } 
     return n; 
    } 

    public void clear() { 
     q.clear(); 
    } 



    public Object[] toArray(Object[] a) { 
     Object[] res = q.toArray(a); 
     for (int i = 0; i < res.length; i++) { // unpacking 
      res[i] = ((FIFOEntry)res[i]).entry; 
     } 
     return res; 
    } 



    public Iterator iterator() { 
     final Iterator it = q.iterator(); 
     return new Iterator() { 
      public void remove() throws UnsupportedOperationException, IllegalStateException, ConcurrentModificationException { 
       it.remove(); 
      } 

      public Object next() throws NoSuchElementException, ConcurrentModificationException { 
       return ((FIFOEntry)it.next()).entry; 
      } 

      public boolean hasNext() { 
       return it.hasNext(); 
      } 
     }; 
    } 

    public int hashCode() { 
     return q.hashCode(); 
    } 

    public boolean equals(Object obj) { 
     return q.equals(obj); 
    } 


    /** 
    * Wrapping class which adds creation ordering to a {@link Comparable} object. 
    * Based on the code in the javadoc for {@link PriorityBlockingQueue} 
    * 
    * 
    */ 
    private static class FIFOEntry implements Comparable { 
     private final static AtomicLong seq = new AtomicLong(); 
     private final long seqNum; 
     private final Comparable entry; 
     public FIFOEntry(Comparable entry) { 
      seqNum = seq.getAndIncrement(); 
      this.entry = entry; 
     } 

     public int compareTo(Object other) { 
      FIFOEntry o = (FIFOEntry) other; 
      int res = entry.compareTo(o.entry); 
      if (res == 0 && o.entry != this.entry) 
       res = (seqNum < o.seqNum ? -1 : 1); 
      return res; 
     } 
     public int hashCode() { 
      final int prime = 31; 
      int result = 1; 
      result = prime * result + ((entry == null) ? 0 : entry.hashCode()); 
      return result; 
     } 
     public boolean equals(Object obj) { 
      if (this == obj) 
       return true; 
      if (obj == null) 
       return false; 
      if (getClass() != obj.getClass()) 
       return false; 
      FIFOEntry other = (FIFOEntry) obj; 
      if (entry == null) { 
       if (other.entry != null) 
        return false; 
      } else if (!entry.equals(other.entry)) 
       return false; 
      return true; 
     } 

     public String toString() { 
      return entry.toString(); 
     } 
    } 

} 
相關問題