Java 同步块(synchronized block)意外行为

标签 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
    {
        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();
        }
    }
}

我原以为一次只有一个线程可以使用 synchronized block ,它会打印如下内容,每次输入和输出之间有 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

谁能帮忙解释一下?

最佳答案

非常简单:您的a 不会在您的任何Experimenter 之间共享;它是一个实例变量,每个 Experimenter 一个。顺便说一句,volatile 在这种情况下几乎没用。

如果你想要一个共享锁,让它成为一个private static final变量。在这种情况下也不需要 volatile!

但我会选择@JBNizet 的解决方案,它更简洁。

编辑:为什么是final?因为它保证一旦初始化就永远不会改变;但是 final 变量最重要的方面来自 Java 内存模型,它指出 final 变量的初始化先于任何读取这个变量。这是一个非常强大的规则。

关于Java 同步块(synchronized block)意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27705992/

相关文章:

java - 包含其他对象的对象的同步方法

java - 如何将数学工作拆分为工作线程 Java

java - 两个线程同时访问同一个ArrayList?

java - Try block 如何知道代码中的哪一行语句必须抛出异常

multithreading - 在JRuby gem中使用线程安全初始化

Java 读取图像 - java.lang.OutOfMemoryError

C# Winforms : A thread that can control the UI and can "sleep" without pausing the whole program. 怎么办?

java - 如何让两个线程等待对方的结果?

java - 使用java将英国邮政编码分成两个主要部分

java - 与 Java 相比,Python 中的 Stooge Sort 指数慢?