Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

synchronized, not always true?

Does the synchronized block always works fine? I am confused now! Am I wrong when using synchronized keyword?

The code snippet is as following:

package com.company;

public class Main {

    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            new MyThread().start();
        }
    }
}

class MyThread extends Thread {

    // no atomic
    private static Integer count = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (count) {
            //synchronized (this) {

                if (count > 100)
                    break;

                count++;
                System.out.println("ThreadId:" + currentThread().getId() + ","
                        + "inc MyThread.count to : " + count);
            }

        }
    }
}

the result is:

ThreadId:10,inc MyThread.count to : 2
ThreadId:9,inc MyThread.count to : 2
ThreadId:9,inc MyThread.count to : 4
ThreadId:9,inc MyThread.count to : 5
ThreadId:9,inc MyThread.count to : 6
....

I don't know why Thread 10 and 9 output the same value.

like image 536
zhangjie Avatar asked Jul 06 '15 10:07

zhangjie


People also ask

What is true about synchronizing?

The synchronized keyword prevents concurrent access to a block of code or object by multiple threads. All the methods of Hashtable are synchronized , so only one thread can execute any of them at a time.

Why is synchronized not working in Java?

Java synchronisation only works if the object is locked by all threads. If the java threads are locks for different instances of class objects, then the synchronisation will not work. All java threads should try to lock the same object, and if the lock is not available, the thread will wait until the lock is released.

Why must wait () always be in synchronized block?

As Michael Borgwardt points out, wait/notify is all about communication between threads, so you'll always end up with a race condition similar to the one described above. This is why the "only wait inside synchronized" rule is enforced.

Why wait () notify () and notifyAll () methods have to be called from synchronized method or block?

Calling notify() or notifyAll() methods issues a notification to a single or multiple threads that a condition has changed and once the notification thread leaves the synchronized block, all the threads which are waiting for fight for object lock on which they are waiting and lucky thread returns from wait() method ...


1 Answers

You are doing absolutely the wrong thing. First, you synchronize on the updated field. The synchronization will be kept on the object which was in the count variable upon synchronization block entry, but you modify it later. So if the second thread is started when first one already incremented a value, then first will be synchronized on Integer.valueOf(0) and second on Integer.valueOf(1) and they will not wait for each other.

The second problem is that you synchronizing on the Integer which is cached for small values and may be reused in completely different part of program, so you may end up waiting for something completely unrelated.

Note that synchronization on this will not help either as this is the MyThread object which is different in every thread.

You can fix your code synchronizing on some shared object which does not change through the execution. It's better to create a special lock object for this purpose:

class MyThread extends Thread {
    private static final Object lock = new Object();
    // no atomic
    private static Integer count = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                ...
            }
        }
    }
}
like image 69
Tagir Valeev Avatar answered Sep 29 '22 13:09

Tagir Valeev