Monday, January 30, 2012

Thread Safe Blocking List

In Java Concurrent Package there are many useful concurrent synchronizer classes such as BlockingQueue, Semaphore, CountDownLatch and CyclicBarrier. But what if we want an bounded List with insertion order preserved where if the upper limit of the List is met new insertions must be blocked until some elements are removed. The following BlockingList implementation does exactly that. This List uses a Semaphore to synchronize the flow of adding and removing. When the maximum amount of elements are in the List and another call to add is made, the add will be blocked until an element is removed from the List.
import java.util.*;
import java.util.concurrent.*;

/**
 * @author Shazin Sadakath
 *
 */

public class BlockingList<T> {
    private final Semaphore semaphore;
    private final List<T> list = Collections.synchronizedList(new ArrayList<T>());

    public BlockingList(int max) {
        semaphore = new Semaphore(max);        
    }    

    public boolean add(T t) throws InterruptedException {
        semaphore.acquire();
        boolean result = false;
        try {
            result = list.add(t);
        } finally {
            if(!result) {
                semaphore.release();
            }
        }
        return result;
    }

    public T remove(int index) {
        T result = null;
        try {
            result = list.remove(index);
        } finally {
            if(result != null) {
                semaphore.release();
            }
        }
        return result;
    }

    public T get(int index) {
        return list.get(index);
    }

    public int indexOf(T t) {
        return list.indexOf(t);
    }

    public T removeIfPresent(T t) {
        T result = null;
        synchronized(list) {
            if(list.contains(t)) {
                result = remove(indexOf(t));
            }
        }
        return result;
    }

    public boolean putIfAbsent(T t) throws InterruptedException {
        boolean result = false;
        synchronized(list) {
            if(!list.contains(t) && semaphore.availablePermits() != 0) {
                result = add(t);
            }
        }    
        return result;
    }
}

No comments: