为什么这个空的同步块会影响程序的输出?

时间:2018-04-26 13:59:36

标签: java concurrency synchronization output synchronized

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

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) {}
        }
    }
}

4 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

同步的机制可以像这样总结

allbaselevels

它基本上就像你使用了锁,其中锁是f

因此,即使您的块没有做什么也不等待,在此等待时间内f不可用。因此,即使您的块中只有等待

,它也会同步您的程序

答案 2 :(得分:0)

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

第一次在MainClass中:

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

第二次在SyncTest实例本身由&#34;这&#34;:

synchronized (this) {}

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

答案 3 :(得分:0)

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

你的主题&#34;同步&#34; (即尽管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将直接滑入100ms小睡之间的中断之一,空同步块不会再影响任何内容了。

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