简体   繁体   中英

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.

I'm currently working on a LayerManager in a graph routing problem. 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. 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. 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
  2. Add it as a field to Layer class

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

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>> . The idea is to hold free Layers inside of 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. 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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