2012-05-02 26 views
6

Używam PriorityBlockingQueue z polem priorytetu. W moim teście używam System#currentTime() dla priorytetów - te same priorytety są uzyskiwane przez komputer będący tak szybki, że milisekundy są takie same (lub bardziej podobne do milisekund na komputerze ma margines błędu).Dlaczego funkcja PriorityQueue nie zachowuje się jak kolejka?

Gdy priorytety są takie same, kolejka działa tak, jakby była stosem, co wydaje się dziwne. Czy istnieje alternatywa, aby kolejka działała tak, jakby była normalną kolejką (czyli raczej FIFO niż zachowanie LIFO), gdy priorytety elementów są takie same?

Odpowiedz

11

Operacje na tej klasie nie gwarantują uporządkowania elementów o jednakowym priorytecie. Jeśli chcesz wymusić zamówienie, możesz zdefiniować niestandardowe klasy lub komparatory, które używają klucza drugorzędnego, aby zerwać więzy w priorytetach podstawowych.

The PriorityBlockingQueue docs themselves powiedzieć ci to, i jak się z nim obejść, jeśli musisz.

+1

Obejrzałem dokumenty, ale oczekiwałem, że już istnieje klasa narzędziowa do tworzenia kolejki, a nie stosu. Jeśli ustawię kolejkę, powinien przejść do tyłu i przeskoczyć kolejkę, jeśli ma wyższy priorytet. – Ben

+2

Dlaczego? Większość użytkowników używa 'PriorityBlockingQueue' _z różnymi priorytetami._ –

+2

, ponieważ stos nie jest kolejką lub jest tylko semantyką? – Ben

2

Nie sądzę, że kolejka priorytetowa gwarantuje kolejność uzyskiwania równych elementów. Jedną z opcji jest uelastycznienie priorytetu - wypychanie ujemnego rozmiaru kolejki podczas przesuwania elementu wraz z jego priorytetem i porównywanie tych wartości dla elementów o równym priorytecie.

1

Wystarczy utworzyć PriorityBlockingQueue z własnym Komparatorem, który uwzględnia czas utworzenia (patrz http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/PriorityBlockingQueue.html#PriorityBlockingQueue(int, java.util.Comparator)). Może zajść potrzeba zmiany kluczy z prostej daty na klasę Data i licznik, gdzie ta ostatnia otrzyma globalnie inkrementację przy każdym utworzeniu (pole statyczne nowej klasy klucza); to nie jest tak naprawdę FIFO, ale raczej First Created First Out.

Lub po prostu zaimplementuj własną klasę PriorityQueueFifo.

0

Innym rozwiązaniem jest utrzymanie licznika w testach, których używasz dla priorytetu, i które zwiększasz przy każdym wstawieniu. W ten sposób kolejka priorytetowa będzie miała w testach kolejność FIFO, ale będzie wyglądała jak dowolna kolejka priorytetów.

Powiązane problemy