简体   繁体   中英

Class has 2 synchronized methods..when a thread is inside second method can another thread enter into first method?

I know that question "Do two synchronized methods execute simultaneously" have been asked before and the answer given was " No. Only one thread can hold the lock of the object. And then it's only that thread that can enter the synchronized methods on that object." However, if its true then please help me understand the output of below code :

public class SynchronizationMistake {

public  int count;

public synchronized int getCount()
{
    return count;
}
public synchronized String incrementCount()
{
    count++;
    return"";
}

public static void main (String args[])
{
    SynchronizationMistake syn = new SynchronizationMistake();
    Thread first = new Thread(syn.new readIncrementCount(syn),"First");
    Thread second = new Thread(syn.new readIncrementCount(syn), "Second");
    Thread third = new Thread(syn.new readIncrementCount(syn), "Third");

    first.start();
    second.start();
    third.start();

}
private class readIncrementCount implements Runnable
{

    SynchronizationMistake syn;
    readIncrementCount(SynchronizationMistake syn)
    {
        this.syn = syn;
    }
    @Override
    public void run() {

        System.out.println("I am "+Thread.currentThread().getName()+".Count is "+ syn.getCount());
        System.out.println("I am "+Thread.currentThread().getName()+".Incrementing count now"+syn.incrementCount());
        System.out.println("I am "+Thread.currentThread().getName()+". After Increment Count is "+ syn.getCount());


    }

}

}

Output is :
I am First.Count is 0
I am First.Incrementing count now
I am First. After Increment Count is 1
I am Third.Count is 0
I am Second.Count is 0
I am Third.Incrementing count now
I am Second.Incrementing count now
I am Third. After Increment Count is 3
I am Second. After Increment Count is 3

Output varies every time I run this program. My doubt is when Second/Third thread got the CPU why it didn't read 'count' as 1 ( updated by first thread)? in other words while First thread had lock on 'syn' and was updating the count to 1 how did Second/Third thread managed to enter into 'getCount'method.

The statement System.out.println("I am "+Thread.currentThread().getName()+".Count is "+ syn.getCount()); is not executed in an atomic way. The part syn.getCount() can be executed way before the println . This also seems to happen in your example. All the threads do the syn.getCount() first, the count is still 0 at that time, and only then execute the rest.

What happens with this particular execution you posted is that all three threads read the counter with a value of zero, but thread one has the chance to complete all of its output before others, ie access to the counter is correctly synchronized, but later prints show older values due to output buffering.

Try to put a sleep after the start of the first thread and this should be less probable to happen again.

As Henry mentioned all the threads may first execute the syn.getCount(), and then execute the syn.incrementCount. I have modified your code slightly to change the println statements which gives a better picture...

public class SynchronizationMistake {

public  int count;

public synchronized int getCount()
{
    return count;
}

public synchronized String incrementCount() {

    System.out.println("I am " + Thread.currentThread().getName() + ", incrementing the count from " + count);
    count++;
    System.out.println("I am " + Thread.currentThread().getName() + ", incremented the count to " + count);
    return"";
}

public static void main (String args[])
{
    SynchronizationMistake syn = new SynchronizationMistake();
    Thread first = new Thread(syn.new readIncrementCount(syn),"First");
    Thread second = new Thread(syn.new readIncrementCount(syn), "Second");
    Thread third = new Thread(syn.new readIncrementCount(syn), "Third");

    first.start();
    second.start();
    third.start();

}
private class readIncrementCount implements Runnable
{

    SynchronizationMistake syn;
    readIncrementCount(SynchronizationMistake syn)
    {
        this.syn = syn;
    }
    @Override
    public void run() {

        System.out.println("Current count is " + syn.getCount());
        System.out.println(syn.incrementCount());
        System.out.println("Current count is " + syn.getCount());
    }

}

}

Different outputs can be as follows...

Output #1 :

 Current count is 0
 I am Second, incrementing the count from 0
 Current count is 0
 I am Second, incremented the count to 1

 Current count is 1
 I am First, incrementing the count from 1
 I am First, incremented the count to 2

 Current count is 2
 Current count is 2
 I am Third, incrementing the count from 2
 I am Third, incremented the count to 3

 Current count is 3

Output #2 :

Current count is 0
Current count is 0
Current count is 0
I am Second, incrementing the count from 0
I am Second, incremented the count to 1

I am Third, incrementing the count from 1
I am Third, incremented the count to 2

I am First, incrementing the count from 2
I am First, incremented the count to 3

Current count is 3
Current count is 3
Current count is 3

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