Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java同步块意外行为_Java_Multithreading_Synchronized - Fatal编程技术网

Java同步块意外行为

Java同步块意外行为,java,multithreading,synchronized,Java,Multithreading,Synchronized,我有以下代码: 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

我有以下代码:

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
但是,我得到了以下信息。所有输入,5秒后,所有输出:

start
start
start
start
start
in
in
in
in
in
out
out
out
out
out

有人能解释一下吗?

每个线程都在自己的锁上同步,因为每个线程都使用自己的实验者实例,而每个实验者实例都有自己的整数实例作为锁。如果希望线程同步,则需要在所有实例之间共享唯一的锁。顺便说一句,您不应该使用整数。请使用简单对象:

final Object sharedLock = new Object();
Thread a = new Thread(new Experimenter(sharedLock), "a");
Thread b = new Thread(new Experimenter(sharedLock), "b");
...
最后一个关键字的使用:
这不是严格需要的。但是锁,特别是当它们被声明为字段时,应该是最终的,以确保您不会意外地为变量分配新值,这将导致线程使用两个不同的锁对象,非常简单:您的
a
不会在任何
实验者之间共享;它是一个实例变量,每个
实验者一个
。顺便说一句,
volatile
在这种情况下几乎没有用处

如果需要共享锁,请将其设为
私有静态final
变量。在这种情况下也不需要使用
volatile

但我会选择@JBNizet的解决方案,它更干净


编辑:为什么
最终版
?因为它保证在初始化后不会更改;但是
final
变量最重要的方面来自Java内存模型,它指出
final
变量的初始化发生在读取该变量之前。这是一条非常有力的规则。

这肯定会对你有用

public void funk() throws InterruptedException
{
    synchronized (Experimenter.class)
    {
        System.out.println("in");
        Thread.sleep(5000);
        System.out.println("out");
    }
}

将字段
a
声明为
static
,它将按预期工作。在代码中,该字段是实例成员,因此实际上有五个不同的监视器

你能解释一下“最终版”的必要性吗?它不是严格需要的。但是锁,特别是当它们被声明为字段时,应该是最终的,以确保不会意外地为变量分配新值,这将导致线程使用两个不同的锁对象。请您将此添加到您的答案中,以便更好地帮助未来用户?您能解释一下“final”的必要性吗?然后他必须使用类级锁???@Prashant不,基本上他不需要;但无论使用哪个锁,它都必须在所有线程之间共享。一个
private static final
变量是一个解决方案,还有其他解决方案,比如@JBNizet(我认为它更干净),如果您使用的是类级锁,那么变量应该是静态的,就像其他一些解决方案一样!!!