2009-07-16 19 views
9

Czy działa następująca podstawowa pula obiektów? Mam bardziej wyrafinowany, oparty na tym samym pomyśle (tj. Utrzymywanie zarówno semafora, jak i BlockingQueue). Moje pytanie brzmi - czy potrzebuję zarówno Semafora, jak i BlockingQueue? Czy mam rację, że nie muszę wykonywać żadnej synchronizacji?Czy działa ta podstawowa pula obiektów Java?

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

jakiegokolwiek powodu robisz to sam? Apache Commons Pool robi to z półki. – skaffman

+3

Co ApacheCommonsPool zapewnia, że ​​blockingQueue nie? Pobiera dużą bibliotekę, aby zdefiniować duży zestaw "standardowych" interfejsów, gdy java.util.concurrent.BlockingQueue obsługuje już wszystkie zdefiniowane operacje. – bhan

+0

@skaffman możesz pomóc http://stackoverflow.com/questions/43860936/create-objects-in-genericobjectpool – Tony

Odpowiedz

0

Może powinieneś sprawdzić, czy obiekty istnieją, to jedyna rzecz, którą mam.

Edytuj: Nie przeczytałem dokładnie tego kodu. Więc trochę streściłem post. :(

2

UŻYCIA() zamiast sondzie() i umieścić() zamiast add(). Semafor jest wtedy całkowicie zbędny, więc można po prostu pozbyć. Ale tak, że wygląda dobrze.

13

Jak zostało wskazane, sam ograniczonym BlockingQueue byłaby wystarczająca na przykład, następujący kod będzie robić to, co chcesz.

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); 
    } 
} 

Ponadto, warto rozważyć wsparcie czasowego wersję pożyczyć() za pomocą BlockingQueue.poll().

Jeśli nie masz ab Zablokowana blokująca struktura danych kolejki, następnie możesz nałożyć semafor na dowolną strukturę danych, aby utworzyć bezpieczne i powiązane zachowanie wątku.

+0

Przyjemny i czysty przykład - ale moim wyborem byłoby uczynienie klasy Pool bardziej abstrakcyjną niż ostateczną i dodanie abstrakcji " Zamiast tego należy użyć metody T createExpensiveObject(). – mindas

+0

Uświadomiłem sobie, że moja sugestia nie zadziała, ponieważ twoje rozwiązanie statycznie inicjalizuje bufor wewnątrz konstruktora. Postaram się zmodyfikować Twój przykład pod kątem możliwości tworzenia kosztownych obiektów na żądanie. – mindas

1

Jego wartość nic nie warta, że ​​obiekt ArrayBlockingQueue tworzy obiekt po wprowadzeniu z niego. Tak więc twoja pula nie będzie faktycznie zapisywać obiektów. To może pomóc tylko wtedy, gdy twoje obiekty są kosztowne do stworzenia.

5

Nieco zmodyfikowany przykład sjlee; umożliwienie tworzenia kosztownych przedmiotów na żądanie. Moja sprawa nie wymagała blokowania, dlatego zastąpiłem to nie blokującym typem kolejki. Jako korzyść nie trzeba zajmować się 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

To nie jest idealne. Stworzysz tyle drogich obiektów, ile potrzeba, a jednocześnie twoja kolejka ma nieograniczony wzrost. Punktem puli jest maksymalny rozmiar. –

+0

Wygląda na to, że przegapiłeś kluczowy element w tytule pytania: ** podstawowy **. Nie projektujemy tutaj pełnego rozwiązania; czasami ** podstawowy ** obejmuje wszystkie potrzeby. – mindas

3

Może użyć stosu zamiast kolejki? Daje to szansę na uzyskanie obiektu, który nadal znajduje się w pamięci podręcznej procesora.

0

Oto jedna bardziej prosta i kompletna pula dla drugiej. To jest lepsze niż najprostsze i jest proste.

Od 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()); 
     } 
    } 
}