Reputation: 1578
I have the following code :
public class Experimenter implements Runnable
{
private volatile Integer a = new Integer(0);
public Experimenter() throws Exception
{
System.out.println("start");
}
public void funk() throws InterruptedException
{
synchronized (a)
{
System.out.println("in");
Thread.sleep(5000);
System.out.println("out");
}
}
public static void main(String[] args) throws Exception
{
Thread a = new Thread(new Experimenter(), "a");
Thread b = new Thread(new Experimenter(), "b");
Thread c = new Thread(new Experimenter(), "c");
Thread d = new Thread(new Experimenter(), "d");
Thread e = new Thread(new Experimenter(), "e");
a.start();
b.start();
c.start();
d.start();
e.start();
}
@Override
public void run()
{
try
{
funk();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
I had expected since only one thread could use the synchronized block at a time, it would print something like the following, with a 5 second gap between each in and out :
start
start
start
start
start
in
out
in
out
in
out
in
out
in
out
But instead, I get the following. All the ins, 5 seconds later, all the outs.:
start
start
start
start
start
in
in
in
in
in
out
out
out
out
out
Could someone help explain this?
Upvotes: 2
Views: 70
Reputation: 692131
Each thread synchronizes on its own lock, since each thread uses its own Experimenter instance, and each Experimenter instance has its own Integer instance serving as a lock. If you want the threads to synchronize, you need to share a unique lock between all instances. You shouldn't use an Integer, BTW. Use a simple Object:
final Object sharedLock = new Object();
Thread a = new Thread(new Experimenter(sharedLock), "a");
Thread b = new Thread(new Experimenter(sharedLock), "b");
...
The use of the final keyword : It's not strictly needed. But locks, especially when they're declared as fields, should be final to make sure you don't accidently assign a new value to the variable, which would cause threads to use two different lock objects
Upvotes: 2
Reputation: 121820
Quite simple: your a
is not shared between any of your Experimenter
s; it is an instance variable, one per Experimenter
. And the volatile
is pretty much useless in this situation by the way.
If you want a shared lock, make it a private static final
variable. And no need for volatile
in this situation either!
But I would go with @JBNizet's solution which is much cleaner.
EDIT: why final
? Because it is guaranteed to never change once initialized; but the most important aspect of a final
variable comes from the Java Memory Model, which states that the initialization of a final
variable happens-before any read of this variable. Which is a very powerful rule.
Upvotes: 3
Reputation: 1745
Declare the field a
as static
and it will work as expected. In your code the field is an instance member, so you have in fact five different monitors.
Upvotes: 1
Reputation: 2655
this will surely work for you
public void funk() throws InterruptedException
{
synchronized (Experimenter.class)
{
System.out.println("in");
Thread.sleep(5000);
System.out.println("out");
}
}
Upvotes: 1