【问题标题】:Why does this empty synchronized block affect the output of the program? [closed]为什么这个空的同步块会影响程序的输出? [关闭]
【发布时间】:2018-04-26 13:59:35
【问题描述】:

所以当我注意到程序中显示的空同步块导致输出同步时,我只是在搞乱基本并发。块里什么都没有,为什么会这样呢?

public class MainClass {

    public static void main(String[] args) throws InterruptedException {
        SyncTest f = new SyncTest();
        f.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("MAIN THREAD:" + i);
            Thread.sleep(500);
               synchronized (f) {
                for (int t = 0; t < 15; t++) {
                    Thread.sleep(100);
                }
            }
        }
    }
 }

class SyncTest extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                System.out.println("OTHER THREAD: " + i);
                Thread.sleep(1300);
                synchronized (this) {} //Why does this have an effect on the output when commented?
            } catch (InterruptedException ex) {}
        }
    }
}

【问题讨论】:

  • synchronized 命令的目的是在线程之间进行同步。为什么你会认为它没有任何效果,只是因为它不包含任何代码?
  • 你是什么意思causes the outputs to sync up
  • 自己复制并粘贴代码,您可以看到输出有块存在和没有块时会发生什么。

标签: java concurrency synchronization output synchronized


【解决方案1】:

同步的机制可以这样总结

synchronized(f) { //wait for no-one use f
    // do some stuff
    //nobdy can use f during this time
} //free f, other can use it

它基本上就像你使用了一个锁,锁是 f

因此,即使您的块除了等待什么都不做,在此等待时间内 f 也不可用。因此,即使您的块中只有等待,它也会同步您的程序

【讨论】:

    【解决方案2】:

    如果指定的锁已被另一个线程占用,则执行流程不会进入synchronized 块。 总是这种情况,即使同步块根本不包含任何代码。

    您的示例中的锁是同一个对象(SyncTest 的实例。)因此,当非空同步块正在运行时,空的将等待它完成。在这种情况下,由于 Thread.sleep() 调用的排列方式,输出结果很可能会同步。

    【讨论】:

      【解决方案3】:

      你已经被同一个对象同步了 2 次。

      第一次进入 MainClass:

      SyncTest f = new SyncTest();
      synchronized (f) {...}
      

      “this”在 SyncTest 实例本身中的第二次:

      synchronized (this) {}
      

      您的程序中有 2 个线程:主线程和 SyncTest 线程。 每个线程都通过 SyncTest 对象到达同步点,并等待另一个线程退出同步部分。

      【讨论】:

        【解决方案4】:

        Berry's answer 总结了synchronized 所做的事情,并提到块的内容无关紧要。所以问题不是真正为什么行为会发生变化,而是为什么会发生如此剧烈的变化。

        你的线程“同步”(即一个一个地记录,即使otherThread 应该更快一些,有时在mainThread 之前记录两次),因为你的 mainThread 休眠了 1500 毫秒 阻塞同步对象时:

        synchronized (f)
        {
            for (int t = 0; t < 15; t++)  // this is
            {                             // (roughly)
                Thread.sleep(100);        // equivalent to 
            }                             // Thread.sleep(1500);
        }
        

        这意味着mainThread 不会给otherThread 机会利用其速度优势(1300 毫秒对 1500 毫秒)并让它等待直到它完成睡眠。将那段代码更改为

        for (int t = 0; t < 15; t++)
        {
            synchronized (f)
            {
                Thread.sleep(100);
            }
        }
        

        并且otherThread 将滑入 100 毫秒小睡之间的中断之一,并且空的同步块不再影响任何东西。

        注意,空的同步块仍然有一点影响,并且可能会稍微改变日志的顺序,因为otherThread 可能仍然需要等待一点(但最多只有 100 毫秒,而不是1500 毫秒)。不过,它不会再导致如此严格的来回。

        【讨论】:

          猜你喜欢
          • 2022-11-06
          • 1970-01-01
          • 2015-11-26
          • 2011-07-10
          • 2011-08-02
          • 1970-01-01
          • 1970-01-01
          • 2013-02-04
          • 2013-11-12
          相关资源
          最近更新 更多