2011-10-09 12 views
8

Da Javadoc di ArrayBlockingQueueArrayBlockingQueue:ArrayBlockingQueue e aggiungere vs put vs capacità

aggiungere

public boolean add (E e)

Inserts the specified element at the tail of this queue if it is possible 
to do so immediately without exceeding the queue's capacity, returning true 
upon success and throwing an IllegalStateException if this queue is full. 

ho sempre interpretato nel presente comunicato (il parte if it is possible to do so immediattely) come segue:

Se la coda ha capacità libera, l'inserimento avrà esito positivo. Se non c'è spazio vuoto, non ci riuscirà.

Ma la mia comprensione era sbagliata qui.

In un caso semplice ho deciso di utilizzare uno ArrayBlockingQueue per es. 20 elementi (piccola coda) e aventi un filo facendo:

queue.take()

l'altro filo non aggiungere un elemento alla coda tramite il metodo add nonostante la coda era quasi vuoto.

Ho verificato anche tramite debug.

Dopo aver sostituito la chiamata di queue.add(element) a queue.put(element), l'elemento è stato effettivamente aggiunto alla coda.

Quindi cosa c'è di così diverso in questi metodi?

Per quale altro motivo (oltre alla capacità) l'aggiunta non può avvenire?


UPDATE:

public class ConnectionListener implements Observer { 

    public static BlockingQueue<ConnectionObject> queueConnections = new ArrayBlockingQueue<ConnectionObject>(10); 

    @Override 
    public void update(Observable arg0, Object arg1) { 
     ConnectionObject con = ((ConnectionObject)arg1); 
     queueConnections.add(con); 
    } 

} 

ConnectionObject è solo un supporto per i valori stringa.

public class ConnectionObject { 
    private String user; 
    private String ip; 
    //etc 
} 

e il consumatore:

public class ConnectionTreeUpdater extends Thread { 
    @Override 
    public void run() { 
    while(true){ 
    try { 
    final ConnectionObject con = ConnectionListener.queueConnections.take(); 

Se uso add non viene generata un'eccezione, ma elemento non viene aggiunto alla coda.

Solo un pensiero: forse in quanto il consumatore è "in attesa" sulla coda, se per qualche servizio di pulizia interna l'elemento non può essere aggiunto che non verranno aggiunti e non fa eccezione è thrown.Could che essere il caso.

Altrimenti non riesco a capire perché non ci siano eccezioni e con put il codice funziona.

Sono put e add destinati a essere utilizzati in modo diverso?

+0

ho il sospetto che dovevamo prendere e ignorando l'eccezione di essere gettato da 'add()' ma senza vedere il tuo codice è solo una supposizione. Devi pubblicare un piccolo esempio di codice che mostri il problema che stai riscontrando. –

+0

In realtà non ci sono state eccezioni in add. Ho appena fatto 'queue.add' e il codice restituito immediatamente senza aggiungere l'elemento e nessuna eccezione – Cratylus

+0

@ user384706: Per favore possiamo vedere un test case completo e riproducibile che dimostra questo comportamento (' add() 'non lanciare un'eccezione ma anche non aggiungere l'elemento alla coda). – NPE

risposta

14

E 'abbastanza semplice, in realtà:

  • se la coda non è pieno, entrambi i metodi riescono;
  • se la coda è piena, add() non riesce con un'eccezione mentre put() blocchi.

Penso che la documentazione sia abbastanza chiara su quanto sopra. Se non sei d'accordo, e vorrebbe un secondo parere, si potrebbe esaminare il codice sorgente per ArrayBlockingQueue:

public boolean add(E e) { 
    if (offer(e)) 
     return true; 
    else 
     throw new IllegalStateException("Queue full"); 
} 

public boolean offer(E e) { 
    if (e == null) throw new NullPointerException(); 
    final ReentrantLock lock = this.lock; 
    lock.lock(); 
    try { 
     if (count == items.length) 
      return false; 
     else { 
      insert(e); 
      return true; 
     } 
    } finally { 
     lock.unlock(); 
    } 
} 

public void put(E e) throws InterruptedException { 
    if (e == null) throw new NullPointerException(); 
    final E[] items = this.items; 
    final ReentrantLock lock = this.lock; 
    lock.lockInterruptibly(); 
    try { 
     try { 
      while (count == items.length) 
       notFull.await(); 
     } catch (InterruptedException ie) { 
      notFull.signal(); // propagate to non-interrupted thread 
      throw ie; 
     } 
     insert(e); 
    } finally { 
     lock.unlock(); 
    } 
} 
+0

'Se trovi la documentazione ambigua, puoi verificarla guardando il codice sorgente - Beh, c'è una differenza tra i dettagli di implementazione e la documentazione, quindi non sono molto contento di quel consiglio in generale. Se la documentazione non è chiara (anche se penso che sia abbastanza chiaro in questo caso), l'apertura di un bug è più ragionevole, credo (non l'ho fatto per Java, ma più di una volta per msdn [beh, l'api doc win32 è un pasticcio ;-)]) – Voo

+0

@Voo: Vedo il tuo punto. Tuttavia, per un bug report significativo deve esserci un bug (o una ragionevole convinzione che ci sia un bug). In questo caso sia la documentazione che il codice indicano chiaramente la stessa cosa (almeno ai miei occhi). – NPE

+0

Sono d'accordo che in questo caso la documentazione è abbastanza chiara (beh e il codice ovviamente fa la cosa giusta TM). Se la documentazione fosse davvero poco chiara, osservare l'implementazione e supponendo che non potesse mai cambiare sarebbe una cattiva idea. Creare un bug per la documentazione per vedere se si trattasse solo di una supervisione onesta o lasciato indefinito per una buona ragione è il miglior modo di agire (beh, prima googlate ovviamente;)) – Voo

2

Una delle parti più importanti di debug di un problema è scrivendo un banco di prova per assicurarsi quello che pensi stia accadendo davvero sta succedendo. Questo dimostra o confuta la tua teoria.

Il caso di test che segue indica che i metodi in uso si comportano esattamente come la documentazione (che si citi) afferma:

public static void main(String[] args) { 

    final ArrayBlockingQueue<Integer> myQueue = 
      new ArrayBlockingQueue<Integer>(10); 


    Thread t1 = new Thread(new Runnable() { 

     public void run() 
     { 
      int i = 0; 
      while (true) 
      { 
       try 
       { 
        myQueue.add(i); 
        System.out.println("Added to queue! value: " + 
             i + 
             " size: " + myQueue.size()); 
        i++; 
       } 
       catch (Exception e) 
       { 
        System.out.println("add() threw exception, size: " + 
             myQueue.size()); 
        try 
        { 
         Thread.sleep(1000); 
        } 
        catch (InterruptedException ex) 
        { 
         Logger.getLogger(Main.class.getName()).log(Level.SEVERE, 
                    null, ex); 
        } 
       } 
      } 
     } 

    }); 

    Thread t2 = new Thread(new Runnable() { 

     public void run() 
     { 
      while (true) 
      { 
       try 
       { 
        Integer i = myQueue.take(); 
        System.out.println("Took a off the queue! value: " + 
             i + 
             " size: " + myQueue.size()); 
        Thread.sleep(100); 
       } 
       catch (InterruptedException ex) 
       { 
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, 
                   null, ex); 
       } 
      } 
     } 
    }); 

    t1.start(); 
    t2.start(); 

} 
Problemi correlati