2015-11-23 16 views
8

Ecco il codice:Posso usare Collection.size() per sostituire il contatore in questo codice?

public class LogService { 
    private final BlockingQueue<String> queue; 
    private final LoggerThread loggerThread; 
    private final PrintWriter writer; 
    @GuardedBy("this") private boolean isShutdown; 
    @GuardedBy("this") private int reservations; // <-- counter 
    public void start() { loggerThread.start(); } 
    public void stop() { 
     synchronized (this) { isShutdown = true; } 
     loggerThread.interrupt(); 
    } 
    public void log(String msg) throws InterruptedException { 
     synchronized (this) { 
      if (isShutdown) 
       throw new IllegalStateException(...); 
      ++reservations; 
     } 
     queue.put(msg); 
    } 
    private class LoggerThread extends Thread { 
     public void run() { 
      try { 
       while (true) { 
        try { 
         synchronized (LogService.this) { 
          if (isShutdown && reservations == 0) 
           break; 
         } 
         String msg = queue.take(); 
         synchronized (LogService.this) { 
          --reservations; 
         } 
         writer.println(msg); 
        } catch (InterruptedException e) { /* retry */ } 
       } 
      } finally { 
       writer.close(); 
      } 
     } 
    } 
} 

Si tratta di un frammento dal libro Java Concurrency in Practice, e sto pensando di che forse il contatore reservations è inutile come abbiamo potuto usare semplicemente queue.size() per ottenere il numero di elementi in queue.

Ho ragione?

+1

coda 'put' e' get' non sono sincronizzati. la modifica 'prenotazioni' è. –

risposta

5

No, ciò creerebbe effettivamente un deadlock.

È necessario sincronizzare put e take se si desidera utilizzare size in modo parallelo. Ma take sta bloccando e ora avresti una chiamata di blocco take sincronizzata sullo stesso oggetto della chiamata put. take non può richiedere fino a quando qualcosa non è put. put non può essere inserito fino a quando take non si blocca. Questo è un punto morto.

+0

Ho esaminato il codice sorgente del metodo 'put' e' take' e sembra che siano sincronizzati con 'Lock'. – user2916610

+0

@ user2916610 la domanda sarebbe se 'size' è sincronizzato pure. – djechlin

+0

'size' è anche sincronizzato. – user2916610

0

L'utilizzo di "prenotazioni" variabile è una buona progettazione del dominio, perché è molto più significativo di dimensioni, è possibile utilizzare che per esprimere il concetto di dominio come il numero totale di prenotazione disponibili ecc

Sul lato prestazioni

ArrayBlockingQueue - la funzione di dimensione chiamata si tradurrà in lentezza perché acquisisce il blocco per leggere la dimensione e rallenterà anche l'operazione take o put.

LinkedBlockingQueue - La dimensione di chiamata è di lettura atomica/volatile e presenta costi di prestazioni.

Problemi correlati