2015-04-27 15 views
6

Ho cercato una risposta a questa domanda su SO e Google ma non sono riuscito a trovare una soluzione adeguata finora.Implementazione elenco di blocchi Java

Attualmente sto lavorando a un LayerManager in un problema di instradamento grafico. Il gestore è responsabile della fornitura e del ripristino di un set fisso di livelli.

Volevo implementare il modello Consumer-Producer con un elenco di blocco, in modo che le richieste di routing in entrata siano bloccate finché non è disponibile alcun layer libero. Finora ho trovato solo un blocking queue ma poiché non abbiamo bisogno di FIFO, LIFO ma l'accesso casuale a una coda non funziona davvero. Per essere un po 'più preciso, qualcosa come questo dovrebbe essere possibile:

Esiste un modo per raggiungere questo obiettivo?

+0

Che dire java.util.concurrent.PriorityBlockingQueue con il proprio comparatore ? – StanislavL

+0

Grazie. Beh, lo strato non è davvero paragonabile secondo me. corrispondono solo a una determinata richiesta. –

risposta

0

Quello che stai cercando si chiama "Semaforo".

  1. Creare una classe Semaforo
  2. aggiungerlo come un campo a Layer classe

Esempio

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


metodi sincronizzati gestiscono l'accesso concorso

3. Loop oltre getLayer fino

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 
+1

che è un po 'quello che faccio ora, non mi piace questo avviso/attesa modello. è molto più incline agli errori del blocco –

0

Provare a usare Map<String, BlockingQueue<Layer>>. L'idea è di mantenere i livelli liberi all'interno di BlockingQueue. Ogni richiesta ha la sua coda.

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

1 ha un livello per richiesta, anche la mappa non è fissa dimensioni –

+0

@DanielGerber perché esattamente dovrebbe essere un problema? – dit

+0

Perché 1 livello potrebbe richiedere fino a 500 MB di RAM. –

0

Non sono sicuro di aver compreso correttamente la necessità, ma è possibile utilizzare una coda di blocco e inserire i risultati in un elenco. Se non si trova un livello appropriato nell'elenco, chiamare wait() e ricontrollare quando un nuovo elemento viene aggiunto all'elenco dalla coda. Questo suona come potrebbe funzionare concettualmente, anche se il codice qui sotto non farlo bene (io sono abbastanza sicuro che questo non è del tutto correttamente sincronizzato)

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