Synchronizing a crowd in Java

2019-07-21 10:39发布

问题:

I'm writing a demo program to explain how to regulate the concurrency of a crowd of threads in Java, but the result is not as I expected. This is the code:

package parcountSyncStat;
public class Parcount extends Thread {
   private static int N=1000;
   private static Integer x=0;

   public static void main(String[] args) throws InterruptedException {
       Thread[] t = new Thread[N];
       int i;
       for (i = N-1; i >= 0; i--) { 
       t[i]=new Parcount(); 
           t[i].start();
       }
       for ( i=N-1; i>=0; i-- ) t[i].join();
       System.out.println(x);
    }
    public void run() { synchronized(x) { x++; } }
}

In a nutshell, 1000 threads try to increment the same integer x. To preserve consistency, I encacsulate the increment in a synchronized block. The parent thread waits for all processes to finish, and then prints the final value of x, which should be 1000. But it isn't. My question is: why? I'm I wrong somewhere?

Note that I obtain the expected result by implementing a class that encapsulates the integer with a synchronized "Increment" method. But replacing the synchronized with a lock/unlock pair does not work either. I'm using Eclipse and did try both openjdk and oracle jdk, with similar results.

Thanks

回答1:

x++ creates a new Integer object - so every time you run that statement the lock used becomes different. If you want one single lock for all you thread, create an ad hoc object:

private static final Object lock = new Object();

and synchronize on that lock.



回答2:

Thanks to assylias: here is the complete code:

public class Parcount extends Thread {
private static int N=1000;
private static Integer x=0;
private static final Object lock = new Object();

public static void main(String[] args) 
        throws InterruptedException {
    Thread[] t = new Thread[N];
    int i;
      for ( i=N-1; i>=0; i-- ) { 
        t[i]=new Parcount(); 
        t[i].start();
    }
    for ( i=N-1; i>=0; i-- ) t[i].join();
    System.out.println(x);
}
public void run() { synchronized(lock) { x++; } }

}



回答3:

The following code uses the owner of your shared resource x, the class Example, as the instance to synchronize with. You may try changing your code like this:

public class Example extends Thread {

    public static void main(String[] args) throws InterruptedException {
        Thread[] t = new Thread[N];
        for (int i = N - 1; i >= 0; i--) {
            t[i] = new Example();
            t[i].start();
        }
        for (int i = N - 1; i >= 0; i--) t[i].join();
        System.out.println(x);
    }

    private static int N = 1000;
    private static int x = 0;

    @Override public void run() {
        synchronized (Example.class) { x++; }
    }
}