简体   繁体   English

Java阻止列表实现

[英]Java Blocking List Implementation

I searched for an answer to this question on SO and Google but couldn't find a proper solution so far. 我在SO和Google上搜索了这个问题的答案,但到目前为止找不到合适的解决方案。

I'm currently working on a LayerManager in a graph routing problem. 我目前正在处理图形路由问题中的LayerManager。 The manager is responsible for providing and resetting a fixed set of layers. 经理负责提供和重置固定的图层集。

I wanted to implement the Consumer-Producer pattern with a blocking list, so that incoming routing requests are blocked as long no free layer is available. 我想用阻塞列表实现Consumer-Producer模式,以便在没有可用的自由层的情况下阻止传入路由请求。 So far I only found a blocking queue but since we don't need FIFO, LIFO but random access a queue doesn't really work. 到目前为止,我只发现了阻塞队列,但由于我们不需要FIFO,LIFO但随机访问队列并不真正起作用。 To be a little more precise, something like this should be 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);
    }
}

Is there any way to achieve this? 有没有办法实现这个目标?

What you are looking for is called "Semaphore". 您正在寻找的是“信号量”。

  1. Create a Semaphore class 创建一个Semaphore类
  2. Add it as a field to Layer class 将其作为字段添加到Layer类

Example

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


Synchronized methods handle access concurrence 同步方法处理访问并发

3. Loop over getLayer until 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

Try to use Map<String, BlockingQueue<Layer>> . 尝试使用Map<String, BlockingQueue<Layer>> The idea is to hold free Layers inside of BlockingQueue . 我们的想法是在BlockingQueue保留免费图层。 Every request has his own queue. 每个请求都有自己的队列。

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

I am not quite sure I understand your need correctly, but you could consume a blocking queue and put the results into a list. 我不太确定我是否正确了解您的需求,但您可以使用阻塞队列并将结果放入列表中。 If an appropriate layer is not found in the list, call wait() and check again when a new item is added to the list from the queue. 如果在列表中找不到合适的层,则调用wait()并在从队列中将新项添加到列表时再次检查。 This sounds like it could work conceptually, even if the code below doesn't get it right (I am quite sure this is not quite properly synchronized) 这听起来像它可以在概念上工作,即使下面的代码没有正确(我很确定这不是很正确的同步)

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM