Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

A Livelock Solution

0.00/5 (No votes)
21 Nov 2011Public Domain2 min read 24.9K   151  
A solution to livelock problem using ExecutorService and LiveLockSolution interfaces

Introduction to Java Concurrency Problems

Java, with Concurrency API, gives good solutions to deadlock problem: the use of blocks with java.util.concurrent.locks interface and its implementations, such as ReentrantLock class; whereas to solve livelock problem there are not too many documentations online.
Starvation is another problem linked to concurrency, see references section to get in deep.

What is Livelock

A definition of Livelock, from Lessons: Concurrency:

A thread often acts in response to the action of another thread. If the other thread's action is also a response to the action of another thread, then livelock may result. As with deadlock, livelocked threads are unable to make further progress. However, the threads are not blocked — they are simply too busy responding to each other to resume work. This is comparable to two people attempting to pass each other in a corridor: Alphonse moves to his left to let Gaston pass, while Gaston moves to his right to let Alphonse pass. Seeing that they are still blocking each other, Alphone moves to his right, while Gaston moves to his left. They're still blocking each other, so...

My Solution

The solution that I propose uses java.util.concurrent.ExecutorService interface and LiveLockSolution interface that I created.

How to Use LiveLockSolution Interface

With LiveLockSolution, I'll remember to code a method to solve livelock into classes used for datas concurrency.

Java
public interface LiveLockSolution {
    public void liveLockSolution();
}

And this is the Product class that uses blocks and implements LiveLockSolution.

Java
public class Product implements LiveLockSolution{
    private int quantity;
    private boolean endLoop;
    private ReentrantLock lock;
    private Condition cond;
    
    public Product(ReentrantLock lock) {
        this.endLoop = false;
        this.quantity = 0;
        this.lock = lock;
        this.cond = lock.newCondition();
    }
    
    public void produce() {
        lock.lock();
        try {
            this.quantity++;
            System.out.println("Q:" + this.quantity);
            cond.signalAll();
        } finally {
            lock.unlock();
        }        
    }
    
    /**
     * It consumes a product, if there isn't a product wait
     */
    public void consume() {
        lock.lock();
        try {
            while(this.endLoop == false && this.quantity == 0) {
                cond.await();
            }
            if(this.endLoop == false) { 
                this.quantity--;
                System.out.println("Q:" + this.quantity);
            }
            cond.signalAll();
        } catch(Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * To ending all waiting threads that use Product 
     */
    @Override
    public void liveLockSolution() {
        lock.lock();
        try {
            this.endLoop = true; //it says to consume to don't wait any more
            cond.signalAll();
        } finally {
            lock.unlock();
        }
    }

Consumer and Productor classes are present into the zip file now.

How to Use ExecutorService Interface

The ExecutorService interface is the actor into main code (see next example): using awaitTermination method, after stopping all threads, we know if there are running threads into executor pool and so use liveLockSolution to solve livelock problem.

Java
 public static void main(String[] args) {
    try {
        ReentrantLock lock = new ReentrantLock();
        Product obj = new Product(lock);
        Consumer cons = new Consumer(obj);
        Consumer cons2 = new Consumer(obj);
        Producer prod = new Producer(obj);
        
        System.out.println("Start concurrency\n\n");

        ExecutorService es = Executors.newCachedThreadPool();
    
        //executes threads
        es.execute(cons);
        es.execute(cons2);
        es.execute(prod);
        
        //lets execute threads for a second
        Thread.sleep(1000); 
        
        //stops the threads
        prod.stop();
        cons.stop();
        cons2.stop();
        
        //to showdown the executor
        es.shutdown(); 
        //waiting running threads
        while(es.awaitTermination(100, TimeUnit.MILLISECONDS) == false) {
            System.out.println("Waiting threads closing");
            obj.liveLockSolution(); //solve livelock
        }
        System.out.println("Concurrency end");

    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

And that is all, folks!

References

History

  • First release: November 2011

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication