mahmood
mahmood

Reputation: 24705

Updating a shared variable among threads

There is a master list where each entry contains a string array. There is also a slave list which is actually a hash set and each entry is a string. I have wrote two threads to search an item from the slave list in the master list.

There is a member class for stat and I initialize it right before issuing the threads (and not the constructor). Each thread increments the stat by 1 when he wants to search a slave item in the master list.

While in the real code, the master list for each thread is unique, the following sample code uses one master list for two threads.

class myClass {
  private List<String []> mainList;
  private HashSet<String> slaveList;
  private int nThread;
  private int stat;
  public myClass(int i)
  {
    nThread = i;
    mainList = new ArrayList<>(); 
    slaveList = new HashSet<>();
    String [] str1 = {"a1", "a2", "a3"}; 
    String [] str2 = {"b1", "b2", "b3"};
    mainList.add(str1); mainList.add(str2);
    slaveList.add("b2"); slaveList.add("a3");
  }
  public void doProcess() {
    stat = 0;
    for (int i = 0; i < nThread; i++) {
        final int index = i;
        final List<String []> m = mainList;
        final HashSet<String> s = slaveList;
        new Thread(() -> {
            search(m, s, index);   
            System.out.println("done");
        }).start();
    }
  }
  public void search( List<String []> m, HashSet<String> s, int index )
  {
    Iterator<String> itr;
    for ( int x = 0; x < m.size(); x++ ) {
      itr = s.iterator(); 
      while(itr.hasNext()){
        ++stat;
        System.out.println("index=" + index + " master id=" + x + " slave=" + itr.next() + " stat=" + stat);
      }
    }  
  }
}
public class Threadtest {

  public static void main(String[] args) {
    myClass mc = new myClass(2);
    mc.doProcess();
  }
}

The output however looks odd!!

index=0 master id=0 slave=b2 stat=1
index=1 master id=0 slave=b2 stat=1
index=0 master id=0 slave=a3 stat=2
index=1 master id=0 slave=a3 stat=3
index=0 master id=1 slave=b2 stat=4
index=1 master id=1 slave=b2 stat=5
index=0 master id=1 slave=a3 stat=6
index=1 master id=1 slave=a3 stat=7
done
done

The second line should print stat=2. It seems that there is a concurrency issue here. The second thread reads the old value of stat which is 0 but the first thread had to increment it by 1 before the second thread.

The output of another run is

index=0 master id=0 slave=b2 stat=2
index=0 master id=0 slave=a3 stat=3
index=0 master id=1 slave=b2 stat=4
index=1 master id=0 slave=b2 stat=2
index=0 master id=1 slave=a3 stat=5
index=1 master id=0 slave=a3 stat=6
done
index=1 master id=1 slave=b2 stat=7
index=1 master id=1 slave=a3 stat=8
done

As you can see, the stat is printed as 2 on the first line!! How that can be fixed?

Upvotes: 1

Views: 66

Answers (2)

Maurice Perry
Maurice Perry

Reputation: 9651

You could synchronize the part where you use the shared variable:

  while(itr.hasNext()){
    int localStat;
    synchronized(this) {
        localStat = ++stat;
    }
    System.out.println("index=" + index + " master id=" + x + " slave=" + itr.next() + " stat=" + localStat );
  }

But the lists are still shared and unprotected.

Upvotes: 1

Azeem
Azeem

Reputation: 14607

It sure is a synchronization problem in your code.

You might want to use synchronized block for accessing stat variable.

Take a look at the documentation.

Upvotes: 1

Related Questions