0

I tried implementing wait/notify mechanism to modify the ArrayList using two separate threads.

It seems to work fine for first iteration but then for second iteration it waits forever in addToArray() method. I am not able to figure out why is it waiting forever in the method? As per my understanding the other thread (removing an item) should pick up when other thread goes to wait.

Please have a look and point out possible bug if any. I know I can use Vector to have thread-safe operation but that is not what I want.

package threadTest;
import java.util.*;

public class DhagaJava {

    public static void main(String...strings){
        ArrayModification am = new ArrayModification();

        Thread t1 = new Thread(new AddToArray(am));
        Thread t2 = new Thread(new RemoveFromArray(am));
        t1.start();
        t2.start();
    }
}

class ArrayModification{
    boolean added = false;
    ArrayList<Integer> al;

    ArrayModification(){
        al = new ArrayList<Integer>();
    }

    public synchronized void addToArrayList(int x) {
        if (added == true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.al.add(x);
        System.out.println(al);
        System.out.println("Added!! :)");
        added = true;
        notifyAll();
    }

    public synchronized void removeFromList(){
        if( added== false){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(al);     
        this.al.remove(0);
        System.out.println("Removed!! :' ");
        added = false;
        notifyAll();
    }
}

class AddToArray implements Runnable{

    ArrayModification ma;

    AddToArray(ArrayModification m){
        this.ma = m;
    }

    public void run() { 
        for (int i = 0; i<10; i++)
            ma.addToArrayList(i);
    }
}

class RemoveFromArray implements Runnable{

    ArrayModification ma;

    RemoveFromArray(ArrayModification a){
        this.ma = a;
    }

    public void run(){
            ma.removeFromList();
    }
}

class RemoveFromArray implements Runnable{

      ArrayModification ma;

      RemoveFromArray(ArrayModification a){
            this.ma = a;
      }

      public void run(){
            //for(int j=11;j<20; j++)
                  ma.removeFromList();
      }
}

Output is:

[0]
Added!! :)
[0]
Removed!! :' 
[1]
Added!! :)
dsolimano
  • 8,870
  • 3
  • 48
  • 63
Shashank
  • 35
  • 1
  • 9

3 Answers3

1

Rather than re-invent the wheel, just use a CopyOnWriteArrayList. It comes with concurrency out of the box.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

Only problem you have is the removeFromList runs only once (because you commended out the for loop). That’s the reason why there is no second remove in the log and that addToArrayList starts waiting forever (waits for someone remove the item from the list).

I tried your code after removing the comment and works fine!

Adorjan Princz
  • 11,708
  • 3
  • 34
  • 25
0

Your notifyAll is inside the synchronized block. So the other thread may be awaken before he can act. So it may be blocked.

I'm not sure I understood your goal, but this construction could be better :

public void addToArrayList(int x) {
    synchonized(this.al) {
        if (added == true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.al.add(x);
        System.out.println(al);
        System.out.println("Added!! :)");
        added = true;
    }
    notifyAll();
}

But this is very complex. Do you have a more general goal ? Maybe a task queue with only one thread could suit you better : it would be faster, lighter, simpler, and as parallelized (that is not at all).

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758