[英]Java synchronized block unexpected behavior
我有以下代码:
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();
}
}
}
我曾预料到,因为一次只有一个线程可以使用同步块,它会打印如下所示的内容,每个内部之间有5秒的间隙:
start
start
start
start
start
in
out
in
out
in
out
in
out
in
out
但相反,我得到以下内容。 所有的ins,5秒后,所有的出局:
start
start
start
start
start
in
in
in
in
in
out
out
out
out
out
有人可以帮忙解释一下吗?
很简单:你的a
不会在你的任何Experimenter
之间共享; 它是一个实例变量,每个Experimenter
一个。 顺便说一句,在这种情况下, volatile
几乎无用。
如果需要共享锁,请将其private static final
变量。 在这种情况下也不需要volatile
!
但我会选择@ JBNizet的更清洁的解决方案。
编辑:为什么final
? 因为保证在初始化后永远不会改变; 但是final
变量最重要的方面来自Java内存模型,它指出final
变量的初始化发生在任何读取此变量之前。 这是一个非常强大的规则。
每个线程在其自己的锁上同步,因为每个线程使用自己的Experimenter实例,并且每个Experimenter实例都有自己的Integer实例作为锁。 如果希望线程同步,则需要在所有实例之间共享唯一的锁。 你不应该使用整数,BTW。 使用简单的对象:
final Object sharedLock = new Object();
Thread a = new Thread(new Experimenter(sharedLock), "a");
Thread b = new Thread(new Experimenter(sharedLock), "b");
...
使用final关键字:这不是严格需要的。 但是锁,尤其是当它们声明为字段时,锁应该是最终的,以确保您不会意外地给变量分配新值,这将导致线程使用两个不同的锁对象
这肯定会对你有用
public void funk() throws InterruptedException
{
synchronized (Experimenter.class)
{
System.out.println("in");
Thread.sleep(5000);
System.out.println("out");
}
}
将字段a
声明为static
,它将按预期工作。 在您的代码中,该字段是实例成员,因此您实际上有五个不同的监视器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.