简体   繁体   中英

Java Synchronization (for specific example)

package sync.block.lock.on.thisObj;

public class Counter {

    int count = 0;

    public void increment() {
        synchronized (this) {
            count++; // STATEMENT 1
            //System.out.println(count);
        }
        System.out.println(count+" increment"); // STATEMENT 2
        //System.out.println(count);
    }

    public void decrement() {
        synchronized (this) {
            count--; // STATEMENT 3
            //System.out.println(count);
        }
        System.out.println(count+" decrement"); // STATEMENT 4
        //System.out.println(count);
    }

    public static void main(String[] args) throws InterruptedException {

        Counter counter = new Counter();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    counter.decrement();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    counter.increment();
                }
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Main Thread: "+counter.count);


    }
}

Following is the result:

0 increment
1 increment
2 increment
3 increment
4 increment
5 increment
6 increment
0 decrement // How this entry and all the following entries?
6 decrement
5 decrement
4 decrement
3 decrement
2 decrement
1 decrement
7 increment
1 increment
2 increment
0 decrement
1 decrement
0 decrement
Main Thread: 0

I agree for the expected result, sysout should be inside synchronized block.

But what sequence of execution might have caused to produce the entry 0 decrement and all its subsequent entries?

My expected sequence of exection:

STATEMENT 1 - increments 1
STATEMENT 3 - decrements 1
STATEMENT 2 - 0 increment printed

STATEMENT 1
--> possibility for STATEMENT 3 to be executed.But it didn't.Because if it had,next statement would have printed 0.
STATEMENT 2 - 1 increment

STATEMENT 1
--> possibility for STATEMENT 3 to be executed.But it didn't.Because if it had,next statement would have printed 1.
STATEMENT 2 - 2 increment

STATEMENT 1
STATEMENT 2 - 3 increment

STATEMENT 1
STATEMENT 2 - 4 increment

STATEMENT 1
STATEMENT 2 - 5 increment

STATEMENT 1
STATEMENT 2 - 6 increment (at this point,count is 6)

STATEMENT 4 - 0 decrement (it must be 6 , or it must be 7 if STATEMENT 1 is executed before this statment. Why 0??)

EDIT: My understanding based on the "happens-before" relationship of lock release and subsequent acquisition of the same lock :

1) t1 increment acquires lock, count++ (count = 1), releases lock.

2) t2 decrement acquires lock,sees count as 1 since it acquired the same lock and now happens-before relationship is established (memory state at the time of release is visible at the time acquiring the same lock), count-- (count = 0), releases lock.

3) t1 increment prints count (count = 0 made by t2 decrement need not necessarily be visible to t1 since t1 has not yet acquired the lock released by t2 but it may be visible). Here it is visible and prints 0.

4) t1 increment acquires lock and increments and this goes on until count = 6 is printed in t1.

5) t2 decrement prints count (count = 6 made by t1 may be not be visible since t2 has not acquired the lock released by t1). Here it is not visible. At this point value of count visible is 0 (from its previous decrement in step (2)).

...

But what sequence of execution might have caused to produce the entry 0 decrement and all its subsequent entries?

When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.

Source : https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

I agree for the expected result, sysout should be inside synchronized block.

Doing it solves the problem as

    System.out.println(count+" decrement"); // STATEMENT 4

would not be in the "happens-before" context in this case.

About your expected sequence, it is wrong as in your actual you don't specify rules that forces threads to wait/notify if a counter value is reached.
So the execution order is not deterministic.

It could be :

> -1 decrement
> -2 decrement
> -3 decrement
> -4 decrement
> -5 decrement
> -6 decrement
> -7 decrement
> -8 decrement
> -9 decrement
> -10 decrement
> -9 increment
> -8 increment
> -7 increment
> -6 increment
> -5 increment
> -4 increment
> -3 increment
> -2 increment
> -1 increment 
>  0 increment 

if the first thread is not paused before terminating.

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