Search code examples
javamultithreadingsynchronizationtaskdeadlock

Deadlock in Producer - consumer thread


I have a problem with possible deadlock in "producer - consumer task". Everything should be working in following way:

  1. Producer should generate and add int[] arrays to collection
  2. Consumer should take those arrays, put them to second collection and print in output

In debbug mode I have noticed that after a while both taks are suspended on this.wait(); method.

Could you help me and explain what is wrong with this code? :)
Thanks!

Producer task class

public class ProducerTask extends Thread{

private static final Object bufforLock = new Object();
private static LinkedList<Integer[]> buffor;

public ProducerTask(){
    if(buffor == null)
        buffor = new LinkedList<>();
    this.setName("@ProducerTask");
}

@Override
public void run() {
    synchronized (this) {
        try {
            for (int i = 0; i < 100; i++) {
                while (isBufforFull()) {
                    System.err.println("ProducerTask is waiting");
                    this.wait();
                }
                Integer[] randomIntArray = getRandomIntArray();

                addToBuffor(randomIntArray);
            }
        } 
        catch (InterruptedException ex) {
        }
    }
}

public static void removeLast(){
    synchronized(bufforLock){
        buffor.removeLast();
        bufforLock.notifyAll();
    }
}

public static Integer[] getLast(){
    synchronized(bufforLock){
        return buffor.getLast();
    }
}

public static boolean isBufforFull(){
    synchronized(bufforLock){
        return buffor.size() == 10;
    }
}

 public static boolean isBufforEmpty(){
    synchronized(bufforLock){
        return buffor.isEmpty();
    }
}

public static void addToBuffor(Integer[] array){
    synchronized(bufforLock){
        buffor.addFirst(array);
        bufforLock.notifyAll();
    }
}

public static LinkedList<Integer[]> getBuffor(){
    synchronized(bufforLock){
        return buffor;
    }
}

private Integer[] getRandomIntArray(){
    int maxSize = 10;
    Integer[] array = new Integer[maxSize];
    for(int i = 0 ; i < maxSize ; i++){
        int value = (int) (Math.random() * 100);
        array[i] = Integer.valueOf(value);
    }
    return array;
}
}

Consumer task class

public class ConsumerTask extends Thread {

private static LinkedList<Integer[]> buffor;

public ConsumerTask() {
    if (buffor == null) {
        buffor = new LinkedList<>();
    }
    this.setName("@ConsumerTask");
}

@Override
public void run() {
    synchronized (this) {
        try {
            while (true) {
                while (ProducerTask.isBufforEmpty()) {
                    System.err.println("ConsumerTask is waiting");
                    this.wait();
                } 

                Integer[] array = ProducerTask.getLast();
                this.arraySortByInserting(array);
                this.buffor.addFirst(array);
                ProducerTask.removeLast();
            }
        }
        catch (InterruptedException ex) {}
    }
}

private Integer[] arraySortByInserting(Integer[] aArrayToSort) {

    if(aArrayToSort == null || aArrayToSort.length == 0)
        return null;

    this.printArray(aArrayToSort, "Array before sorting");

    for (int i = 1; i < aArrayToSort.length; i++) {
        int intValue = aArrayToSort[i];
        int j = i;
        while ((j > 0) && (aArrayToSort[j - 1] > intValue)) {
            aArrayToSort[j] = aArrayToSort[j - 1];
            j--;
        }
        aArrayToSort[j] = intValue;
    }


    this.printArray(aArrayToSort, "Array after sorting");

    return aArrayToSort;
}

private void printArray(Integer[] aArray, String aMessage) {

    System.out.print(aMessage + " [");

    for (int intElement : aArray) {
        System.out.print(intElement + " ");
    }

    System.out.print("]");
    System.out.println();
}
}

Solution

  • You need a common object which would be used for inter thread communication.

    Right now you are using this as object on which you get lock on and you notify on bufferLock in producer thread and same applies for consumer thread.

    Remember both are two different instances and both successfully obtain lock on individual objects and then both enters wait state.