1 year ago

#374174

test-img

ErminioB

Java Condition interface example ends in deadlock

Good day, I wrote an example to verify my understanding of the Condition interface in Java - there is a tank and two threads, one to try and put in a random quantity of water, the other to try and remove a random quantity of water. I use a condition to make the first thread to wait when putting water in would exceed the tank capacity and another condition to make the second thread to wait when there is not enough water in the tank. But I end up with both threads waiting forever - I take that, say, one thread gets blocked from putting water in, then the other thread gets also blocked from taking water out and at this point none of the threads can unlock the other one. Did I misunderstand the condition interface or my thread logic is wrong? Thanks! Erminio.

package conditioninterface;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Tank
{
    final static int TANK_CAPACITY = 50;
    
    private int level;
    
    Lock tankLock = new ReentrantLock( true );
    
    Condition tankNotFull = tankLock.newCondition();
    Condition tankNotEmptied = tankLock.newCondition();
    
    
    public Tank( int initLevel )
    {
        level = initLevel;
    }
    
    public void fillTank( int quantityToAdd ) throws InterruptedException 
    {
        tankLock.lock();
        
        try
        {
            while( ( level + quantityToAdd ) > TANK_CAPACITY )
            {
                tankNotFull.await();
            }

            level += quantityToAdd;

            tankNotEmptied.signalAll();
        }
        finally
        {
            tankLock.unlock();
        }        
    }
    
    public int emptyTank( int quantityToRemove ) throws InterruptedException
    {
        int quantity = 0;
        
        tankLock.lock();
        
        try
        {
            while( ( level - quantityToRemove ) < 0 )
            {
                tankNotEmptied.await();
            }

            level -= quantityToRemove;

            tankNotFull.signalAll(); 
        }
        finally
        {
            tankLock.unlock();            
        }
        
        return quantity;
    }
    
    public synchronized int getLevel( )
    {
        return level;
    }
}

public class Main
{
    public static void main( String[] args )
    {
        Tank aTank = new Tank( 0 );
        
        Thread tankFiller = new Thread( ( ) -> 
        {
            int cycles = 1;
            
            while( cycles++ < 20 )
            {
                try
                {
                    aTank.fillTank((int)(Tank.TANK_CAPACITY * Math.random()));
                }
                catch( InterruptedException iE )
                {
                    System.out.println( iE.getMessage() );
                }
                finally
                {
                    System.out.printf( "Tank level: %d\n", aTank.getLevel() );
                }
            }
        });
        
        Thread tankEmpty = new Thread( ( ) -> 
        {
            int cycles = 1;
            
            while( cycles++ < 20 )
            {
                try
                {
                    aTank.emptyTank((int)(Tank.TANK_CAPACITY * Math.random()));
                }
                catch( InterruptedException iE )
                {
                    System.out.println( iE.getMessage() );
                }
                finally
                {
                    System.out.printf( "Tank level: %d\n", aTank.getLevel() );
                }
            }
        });
        
        tankFiller.start();
        
        tankEmpty.start();      
    }
}

I looked around the web for deadlock solutions, but none of them seems to apply to this case.

java

deadlock

0 Answers

Your Answer

Accepted video resources