简体   繁体   中英

Can't understand Synchronized block in java

I was trying to study thread synchronization in java and I came to know about synchronized block. I may be asking a silly question as I don't know much about thread synchronization but in this program I am not understanding the behaviour of the block.

class Table {
    void printTable(int n) { //method not synchronized
        for(int i=1; i<=10; i++) {
            System.out.println(n + " * " + i + " = " + n*i);
            try {
                Thread.sleep(500);
            } catch(Exception e) {
                System.out.println(e);
            }
        }
        System.out.println("Table of " + n + " is completed.");
    }
}

class MyThread extends Thread {
    Table t;
    int num;

    MyThread(Table t, int num) {
        this.t = t;
        this.num = num;
    }

    public void run() {
      synchronized(t) {
        t.printTable(num);
      }
    }
}

class TestSynchronization {
    public static void main(String[] args) {
        Table obj = new Table(); //only one object
        MyThread t1;
        MyThread t2;

        t1 = new MyThread(obj, 10);
        t2 = new MyThread(obj, 17);

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

It's output is like this:

10 * 1 = 10
10 * 2 = 20
10 * 3 = 30
10 * 4 = 40
10 * 5 = 50
Table of 10 is completed.
17 * 1 = 17
17 * 2 = 34
17 * 3 = 51
17 * 4 = 68
17 * 5 = 85
Table of 17 is completed.

Which seems proper but when I try to do the same by removing synchronized block from run method and appying it into the obj object of void main it shows different output.

class Table {
    void printTable(int n) { //method not synchronized
        for(int i=1; i<=5; i++) {
            System.out.println(n + " * " + i + " = " + n*i);
            try {
                Thread.sleep(500);
            } catch(Exception e) {
                System.out.println(e);
            }
        }
        System.out.println("Table of " + n + " is completed.");
    }
}

class MyThread extends Thread {
    Table t;
    int num;

    MyThread(Table t, int num) {
        this.t = t;
        this.num = num;
    }

    public void run() {
        t.printTable(num);
    }
}

class TestSynchronization {
    public static void main(String[] args) {
        Table obj = new Table(); //only one object
        MyThread t1;
        MyThread t2;

        synchronized(obj) {
        t1 = new MyThread(obj, 10);
        t2 = new MyThread(obj, 17);
        }

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

Output:

10 * 1 = 10
17 * 1 = 17
10 * 2 = 20
17 * 2 = 34
17 * 3 = 51
10 * 3 = 30
17 * 4 = 68
10 * 4 = 40
10 * 5 = 50
17 * 5 = 85
Table of 17 is completed.
Table of 10 is completed.

Why this is not working in the second case please explain me.

Also suggest me the way in which I can get the same output by using synchronized block in void main if possible.

The difference is where and when the lock to the Table class object was acquired.

In your first example, the lock to the Table object was acquired inside instances of MyThread class. Assume the first instance of MyThread class acquires the table object lock, no other instances of MyThread class will be able to acquire the lock to the table object until the first one released it aka, Thread-level synchronization .

In your second example, the lock to the object was acquired by the driver program, so technically, there is no concurrency issue at this level since the lock is tied to the driver program and not to the individual threads, which is actually kind of process-level synchronization .

Synchronized block is a Room and Synchronized block is applied on a object . In the First Example the Synchronized Block is applied on the Class Table Object. When any thread is trying to access the method it has to first enter the Synchronized Block like a person enter the room and when a thread like t1 enters the block the room is locked until the execution has been finished by t1 , and only after that can thread t2 enter the room.

Without a Synchronized block the threads are interleaving each other and thus the output differs , it may be sometimes the output is correct if t1 finishes execution just before t2 starts but in cases of big application it will interfere and will cause different out put as you mentioned in the second example. So in order to prevent such interleiving we use synchronized blocks or thrcead safe classes like , blocking queue etc.

Synchronized block

   synchronized(mutex){
     x =y;
     y=z;
   }

mutex = mutually exclusive. Block which can be executed by one thread from the list of threads those who share the same object ie mutex

First of all mutex is object and each object in java has a semophore called lock.

if thread A and B has shared mutex as c then Thread A before entering to synchronise block will have to acquire lock ie acquire happen before entrance

and release happen before acquire ie if one thread has already acquired the lock then another thread has to wait until first thread don't release the lock.

another feature of synchronise block is each thread who has acquired the lock need to read all the variable involved in block directly from main memory instead of stall value from cache and have to write those if changed, to main memory before leaving the block.

ie variable value update happens after acquire and memory write happens before release so next thread will have latest value to process.

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