2009-07-16 9 views
9

Il seguente lotto di oggetti di base funziona? Ne ho uno più sofisticato basato sulla stessa idea (cioè mantenendo sia un semaforo che un BlockingQueue). La mia domanda è: ho bisogno sia di Semaphore che di BlockingQueue? Ho ragione che non ho bisogno di fare alcuna sincronizzazione?Questo pool di oggetti Java di base funziona?

import java.util.Collection; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.Semaphore; 

public final class Pool<T> { 

    private final BlockingQueue<T> objects; 
    private final Semaphore permits; 

    public Pool(Collection<? extends T> objects) { 
     // we have as many permits as objects in our pool: 
     this.permits = new Semaphore(objects.size()); 
     this.objects = new ArrayBlockingQueue<T>(objects.size(), false, objects); 
    } 

    public T borrow() { 
     this.permits.acquireUninterruptibly(); 
     // we have a permit, so there must be one in there: 
     return this.objects.poll(); 
    } 

    public void giveBack(T object) { 
     this.objects.add(object); 
     this.permits.release(); 
    } 
} 
+2

Qual è il motivo che state facendo da soli? Apache Commons Pool fa questo sullo scaffale. – skaffman

+3

Che cosa ApacheCommonsPool fornisce che non sia un blockingQueue? Inserisce una grande libreria per definire un ampio set di interfacce "standard" quando un java.util.concurrent.BlockingQueue supporta già tutte le operazioni definite. – bhan

+0

@skaffman puoi aiutare http://stackoverflow.com/questions/43860936/create-objects-in-genericobjectpool – Tony

risposta

0

Forse dovresti controllare che gli oggetti esistano, questa è l'unica cosa che ho.

Modifica: non ho letto il codice attentamente. Quindi ho un po 'alterato il post. :(

2

Usa take() invece che poll(), e mise() al posto di add(). Il semaforo è poi completamente ridondante in modo da poter semplicemente sbarazzarsi di esso. Ma sì, che sembra buono.

13

Come è stato sottolineato, un BlockingQueue limitata da sola sarebbe sufficiente, ad esempio, il seguente codice farà ciò che si vuole:.

import java.util.Collection; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 

public final class Pool<T> { 

    private final BlockingQueue<T> objects; 

    public Pool(Collection<? extends T> objects) { 
     this.objects = new ArrayBlockingQueue<T>(objects.size(), false, objects); 
    } 

    public T borrow() throws InterruptedException { 
     return this.objects.take(); 
    } 

    public void giveBack(T object) throws InterruptedException { 
     this.objects.put(object); 
    } 
} 

Inoltre, si potrebbe prendere in considerazione il sostegno di una versione a tempo di prendere in prestito() utilizzando BlockingQueue.poll().

Se non si dispone di struttura dati a coda bloccata, quindi è possibile imporre un semaforo su qualsiasi struttura dati per creare un comportamento thread safe e bound.

+0

Esempio bello e pulito - ma la mia scelta sarebbe quella di rendere la classe Pool astratta anziché definitiva e aggiungere un abstract " T invece il metodo createExpensiveObject() ". – mindas

+0

Ho appena realizzato che il mio suggerimento non funzionava perché la soluzione inizializza staticamente il buffer all'interno del costruttore. Cercherò di modificare il tuo esempio per la possibilità di creare oggetti costosi su richiesta. – mindas

1

Non vale niente che un oggetto ArrayBlockingQueue crei un oggetto quando si prende una voce da esso. Quindi il tuo pool non salverà effettivamente oggetti. Potrebbe essere utile solo se i tuoi oggetti sono costosi da creare.

5

Un esempio di sjlee un po 'modificato; permettendo la creazione di oggetti costosi su richiesta. Il mio caso non ha richiesto alcuna funzione di blocco, quindi l'ho sostituito con un tipo di coda non bloccante. Come vantaggio, non è necessario gestire InterruptedExceptions.

import java.util.Collection; 
import java.util.Queue; 
import java.util.concurrent.ConcurrentLinkedQueue; 

public abstract class ObjectPool<T> { 

    private final Queue<T> objects; 

    public ObjectPool() { 
     this.objects = new ConcurrentLinkedQueue<T>(); 
    } 

    public ObjectPool(Collection<? extends T> objects) { 
     this.objects = new ConcurrentLinkedQueue<T>(objects); 
    } 

    public abstract T createExpensiveObject(); 

    public T borrow() { 
     T t; 
     if ((t = objects.poll()) == null) { 
      t = createExpensiveObject(); 
     } 
     return t; 
    } 

    public void giveBack(T object) { 
     this.objects.offer(object); // no point to wait for free space, just return 
    } 
} 
+0

Questo non è l'ideale. Creerai tutti gli oggetti costosi di cui hai bisogno simultaneamente in modo che la tua coda abbia una crescita illimitata. Il punto di una piscina è che ha una dimensione massima. –

+0

Sembra che tu abbia perso l'elemento chiave nel titolo della domanda: ** di base **. Non stiamo progettando una soluzione completa qui; a volte ** base ** copre tutte le esigenze. – mindas

3

Forse utilizzare uno stack invece di una coda? Ciò dà la possibilità di ottenere un oggetto che si trova ancora nella cache del processore.

0

Ecco un altro pool semplice e completo per quest'ultimo. È meglio del più semplice ed è semplice.

Da here

/** 
* 
* @see <a href=http://www.javacodegeeks.com/2013/08/simple-and-lightweight-pool-implementation.html>simple pool</> 
*/ 
abstract static class ObjectPool<T> 
{ 
    private ConcurrentLinkedQueue<T> pool; 

    private ScheduledExecutorService executorService; 

    /** 
    * Creates the pool. 
    * 
    * @param minIdle minimum number of objects residing in the pool 
    */ 
    public ObjectPool(final int minIdle) 
    { 
     // initialize pool 
     initialize(minIdle); 
    } 

    /** 
    * Creates the pool. 
    * 
    * @param minIdle   minimum number of objects residing in the pool 
    * @param maxIdle   maximum number of objects residing in the pool 
    * @param validationInterval time in seconds for periodical checking of minIdle/maxIdle conditions in a separate thread. 
    *       When the number of objects is less than minIdle, missing instances will be created. 
    *       When the number of objects is greater than maxIdle, too many instances will be removed. 
    */ 
    public ObjectPool(final int minIdle, final int maxIdle, final long validationInterval) 
    { 
     // initialize pool 
     initialize(minIdle); 

     // check pool conditions in a separate thread 
     executorService = Executors.newSingleThreadScheduledExecutor(); 
     executorService.scheduleWithFixedDelay(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       int size = pool.size(); 
       if (size < minIdle) 
       { 
        int sizeToBeAdded = minIdle - size; 
        for (int i = 0; i < sizeToBeAdded; i++) 
        { 
         pool.add(createObject()); 
        } 
       } else if (size > maxIdle) 
       { 
        int sizeToBeRemoved = size - maxIdle; 
        for (int i = 0; i < sizeToBeRemoved; i++) 
        { 
         pool.poll(); 
        } 
       } 
      } 
     }, validationInterval, validationInterval, TimeUnit.SECONDS); 
    } 

    /** 
    * Gets the next free object from the pool. If the pool doesn't contain any objects, 
    * a new object will be created and given to the caller of this method back. 
    * 
    * @return T borrowed object 
    */ 
    public T borrowObject() 
    { 
     T object; 
     if ((object = pool.poll()) == null) 
     { 
      object = createObject(); 
     } 

     return object; 
    } 

    /** 
    * Returns object back to the pool. 
    * 
    * @param object object to be returned 
    */ 
    public void returnObject(T object) 
    { 
     if (object == null) 
     { 
      return; 
     } 

     this.pool.offer(object); 
    } 

    /** 
    * Shutdown this pool. 
    */ 
    public void shutdown() 
    { 
     if (executorService != null) 
     { 
      executorService.shutdown(); 
     } 
    } 

    /** 
    * Creates a new object. 
    * 
    * @return T new object 
    */ 
    protected abstract T createObject(); 

    private void initialize(final int minIdle) 
    { 
     pool = new ConcurrentLinkedQueue<T>(); 

     for (int i = 0; i < minIdle; i++) 
     { 
      pool.add(createObject()); 
     } 
    } 
}