简体   繁体   中英

java concurrency issue

Why n sometimes equals 1 or 2

private static int n = 0;

private static Thread t1, t2;

private synchronized static void increment() {
    n++;
}

public static void main(String[] args) {
    t1 = new Thread(new Runnable() {
        public void run() {
            increment();
        }
    });

    t2 = new Thread(new Runnable() {
        public void run() {
            t1.start();
            increment();
        }
    });

    t2.start();

    try {
        t2.join();
    } catch(InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(n);
}

Shouldn't the increment method only allow one thread to execute it at any given moment?

Maybe it is the debugger, it seems that when I run it normally I always get 2 but when i debug the code it some times return 1.

It does, however it could happen in either order. You only wait for t2 to finish but not for t1 to finish.

Wait for t1 as well.

private static int n = 0; 

private static Thread t1, t2;

private synchronized static void increment() {  // Lock will be on the "class" Object
    n++;
}

public static void main(String[] args) {
    t1 = new Thread(new Runnable() {
        public void run() {
            increment();
        }
    });

    t2 = new Thread(new Runnable() {
        public void run() {
            t1.start();           
// t1 starts after t2. Now, t1's increment might also be called or t2's increment() might also be called. If t2 calls increment(), then the join() method below (you are joining the in the main thread) will be completed and "n" will be printed (if t1 is not getting appropriate time of execution..)
            increment();
        }
    });

    t2.start();           // t2 starts first

    try {
        t2.join();
    } catch(InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(n); // increment() might not have been called by t1
}

There is no guarantee that one thread would execute before another (even with synchronized condition..). So, you can join on both t1 and t2 . This will ensure you will always get output as 2.

I guess if the increment invocation in the run method of t2 takes place before the increment method of t1 is invoked in t1 's run method, then n is locked and by the time t2 ends, t1 might still be running, but you're printing out n incremented by t2 before t1 's increment is over.

To clarify:

  • t2 starts
  • t2 spawns t1
  • t2 invokes increment before t1 has a chance to
  • n is locked for the duration of t2 's increment
  • main Thread joins t2 before t1 has a chance to increment
  • main Thread prints n before t1 has a chance to increment

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM