【问题标题】:Relationship between Threads and println() statements线程和 println() 语句之间的关系
【发布时间】:2016-03-22 13:32:48
【问题描述】:

我试图创建一些场景来演示可见性问题,同时跨线程共享变量。而且我注意到,在我测试的几乎所有情况下,如果在 run() 中我在使用共享变量的同一代码块中添加了 System.out.println() 语句,则不会产生可见性问题。我举一个例子:

配置详细信息 - Oracle Java6 64 位、Eclipse Juno SR 2

  • 1) 存在可见性问题:

    public class NoVisibility_Demonstration extends Thread {
    boolean keepRunning = true;
    public static void main(String[] args) throws InterruptedException {
        NoVisibility_Demonstration t = new NoVisibility_Demonstration();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning is false");
    }
    public void run() {
        int x = 1;
        while (keepRunning) 
        {
            //System.out.println("If you uncomment this line, the code will work without the visibility issue");
            x++;
    
        }
        System.out.println("x:"+x);
    }
    

    }

输出:线程无限运行

  • 2) 没有可见性问题:

与上面相同的代码,在 run() 中使用未注释的 println() 语句

输出:

...

如果您取消注释此行,代码将在没有可见性问题的情况下运行

如果您取消注释此行,代码将在没有可见性问题的情况下运行

如果您取消注释此行,代码将在没有可见性问题的情况下运行

x:19391

keepRunning 为假

由于我在我尝试的所有示例中都注意到了类似的行为,我想知道在任何 I/O 操作之前 JVM 是否有任何数据完整性检查。

【问题讨论】:

  • while 循环中使用System.out.println() 将对每个循环迭代完成的速度产生相当大的影响。写入控制台是,简单地增加一个int 变量是非常快的。只是需要牢记。
  • @JonK 我注意到在我编写的另一个程序中。是的,差异是巨大的。

标签: java multithreading


【解决方案1】:

PrintWriter 已同步

public void println(String x) {
    synchronized(this) {
        this.print(x);
        this.newLine();
    }
}

在主线程和第二个线程中对System.out.println() 的两次连续调用会在两个线程之间创建一个同步顺序。这意味着在释放监视器(退出同步方法)之前在主线程中发生的所有操作(在您的情况下是变量更新)将被代码看到,在获得监视器后在第二个线程中执行(进入同步方法) .

简单来说,是的,调用System.out.println() 会进行这种同步。

【讨论】:

  • 谢谢。现在清楚多了。尽管我发现无论我是否在主线程中评论 println() 语句,都不会对这一观察结果产生影响。只有 run() 中的 println() 会导致差异。此外,即使我在从 main 启动另一个线程之前放置了 println() 语句,也没有影响。
  • @BimanTripathy 我不知道你为什么会得到这些结果。它们稳定吗?
  • 是的。每次都会产生这种行为。你的意思是你得到的结果和我不一样?
  • 好的,知道了。这是因为在这种情况下,主线程是否知道共享变量的正确状态并不重要。开明!谢谢
【解决方案2】:

此行为是特定于实现的。在 OpenJDK 中,println 的主体是同步的,尽管 API 没有声明它是同步的。

【讨论】:

    猜你喜欢
    • 2017-01-29
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多