Implémentation de la Liste de blocage Java


J'ai cherché une réponse à cette question sur SO et Google mais je n'ai pas trouvé de solution appropriée jusqu'à présent.

Je travaille actuellement sur un LayerManager dans un problème de routage de graphe. Le gestionnaire est responsable de la fourniture et de la réinitialisation d'un ensemble fixe de couches.

Je voulais implémenter le modèle Consommateur-producteur avec une liste de blocage, afin que les demandes de routage entrantes soient bloquées tant qu'aucune couche libre n'est disponible. Jusqu'à présent, je n'ai trouvé qu'une file d'attente de blocage mais puisque nous vous n'avez pas besoin de FIFO, LIFO mais l'accès aléatoire à une file d'attente ne fonctionne pas vraiment. Pour être un peu plus précis, quelque chose comme ça devrait être possible:

/* this should be blocking until a layer becomes available */
public Layer getLayer(){ 

    for ( Layer layer : layers ) {
        if ( layer.isUnused() && layer.matches(request) )
            return layers.pop(layer);
    }
}

Y a-t-il un moyen d'y parvenir?

Author: Maroun, 2015-04-27

3 answers

Ce que vous recherchez est appelé "Sémaphore".

  1. Créer une classe Sémaphore
  2. Ajoutez - le comme champ à la classe de calque

Exemple

 public class Semaphore 
{
    private boolean signal = false;

    public synchronized boolean take() 
    {
       if(this.signal==true)
            return false;  //already in use
       this.signal = true;
       this.notify();
       return true;
    }

     public synchronized void release() throws InterruptedException
     {
        while(!this.signal) wait();
        this.signal = false;
     }


     public boolean isUnused()
     {
         return !signal ;
     }

}


//2.
class Layer
{
    Semaphore sem =null;

    /*your code*/
     /*sem = new Semaphore(); in constructors*/
    public boolean take()
    {
        return this.sem.take();
    }

    public void release()
    {
        this.sem.release();
    }

    public Layer getLayer()
    { 

        for ( Layer layer : layers ) 
        {
         if ( layer.matches(request) && layer.take())
             return layer;
        }

         return null;
    }
}


Les méthodes synchronisées gèrent la concurrence d'accès

3. Boucle sur getLayer jusqu'à

Layer l=null;
while(l==null)
{
    l= getlayer();
    Thread.sleep(100); //set time
}
 // continue
 // do not forget to release the layer when you are done
 0
Author: , 2015-04-27 08:28:09

Essayez d'utiliser Map<String, BlockingQueue<Layer>>. L'idée est de contenir des couches libres à l'intérieur de BlockingQueue. Chaque demande a sa propre file d'attente.

public class LayerQueue {

    Map<String, BlockingQueue<Layer>> freeLayers = Collections.synchronizedMap(new HashMap<String, BlockingQueue<Layer>>());

    public LayerQueue() {
        //init QUEUEs
        freeLayers.put("request-1", new ArrayBlockingQueue<Layer>(1)); // one to one...
        freeLayers.put("request-2", new ArrayBlockingQueue<Layer>(1));
        [...] 
    }

    public void addUnusedLayer(Layer layer, String request) {
        BlockingQueue<Layer> freeLayersForRequest = freeLayers.get(request);
        freeLayersForRequest.add(layer);
    }

    public Layer getLayer(String request) {

        BlockingQueue<Layer> freeLayersForRequest = freeLayers.get(request);

        try {
            return freeLayersForRequest.take(); // blocks until a layer becomes available
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
 0
Author: dit, 2015-04-27 09:36:37

Je ne suis pas sûr de bien comprendre votre besoin, mais vous pouvez consommer une file d'attente de blocage et mettre les résultats dans une liste. Si une couche appropriée n'est pas trouvée dans la liste, appelez wait() et vérifiez à nouveau lorsqu'un nouvel élément est ajouté à la liste à partir de la file d'attente. Cela semble pouvoir fonctionner conceptuellement, même si le code ci-dessous ne fonctionne pas correctement (je suis sûr que ce n'est pas tout à fait correctement synchronisé)

public class PredicateBlockingQueue<Product> {

private final List<Product> products = new LinkedList<Product>();
private final BlockingQueue<Product> queue;
private final Thread consumer;

public PredicateBlockingQueue(int capacity) {
    queue = new ArrayBlockingQueue<Product>(capacity);

    consumer = new Thread() {
        @Override
        public void run() {
            while(!Thread.interrupted()) {
                try {
                    products.add(queue.take());
                    synchronized(queue) {
                        queue.notifyAll();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    consumer.start();
}

public void put(Product product) throws InterruptedException {
    queue.put(product);
}

public Product take(Predicate<Product> predicate) throws InterruptedException {
    Product product;
    while((product=find(predicate))==null) {
        synchronized(queue) {
            queue.wait();
        }
    }
    return product;
}

private synchronized Product find(Predicate<Product> predicate) {
    Iterator<Product> it = products.iterator();
    while(it.hasNext()) {
        Product product = it.next();
        if(predicate.test(product)) {
            it.remove();
            return product;
        }
    }
    return null;
}
 0
Author: Atuos, 2015-04-27 09:39:34