2015-04-27 3 views
6

Я искал ответ на этот вопрос о SO и Google, но пока не нашел подходящего решения.Реализация списка блокировки Java

В настоящее время я работаю над LayerManager в задаче маршрутизации графа. Менеджер отвечает за предоставление и сброс фиксированного набора слоев.

Я хотел внедрить шаблон Consumer-Producer с блокирующим списком, чтобы запросы на входящую маршрутизацию были заблокированы, поскольку свободный доступ к свободному слою невозможен. До сих пор я нашел только blocking queue, но так как нам не нужен FIFO, LIFO, но случайный доступ к очереди на самом деле не работает. Чтобы быть более точным, должно быть возможно что-то подобное:

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

Есть ли способ достичь этого?

+0

насчет java.util.concurrent.PriorityBlockingQueue с вашим собственным Компаратор ? – StanislavL

+0

Спасибо. Ну, слой, на мой взгляд, на самом деле не сравнима. они соответствуют только заданному запросу. –

ответ

0

То, что вы ищете, называется «Семафор».

  1. Создать класс Семафор
  2. Добавьте его в поле Layer класс

Пример

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


Синхронные методы обрабатывать совпадением доступа

3. Цикл по getLayer до

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

Это то, что я делаю сейчас, мне не нравится этот шаблон уведомления/ожидания. это гораздо больше подверженности ошибкам, чем блокировка –

0

Try использовать Map<String, BlockingQueue<Layer>>. Идея состоит в том, чтобы удерживать свободные слои внутри BlockingQueue. У каждого запроса есть своя очередь.

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 есть один слой за запрос, также карта не имеет фиксированного размера –

+0

@ DanielGerber почему именно это должно быть проблемой? – dit

+0

Поскольку 1 слой может потребоваться до 500 МБ ОЗУ. –

0

Я не совсем уверен, что я понимаю вашу потребность правильно, но вы могли бы потреблять очередь блокировки и поместить результаты в список. Если соответствующий слой не найден в списке, вызовите wait() и снова проверьте, когда новый элемент добавлен в список из очереди. Это звучит, как он может работать концептуально, даже если ниже код не получить это право (я совершенно уверен, что это не совсем правильно синхронизированы)

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