所以当我注意到程序中显示的空同步块导致输出同步时,我只是在搞乱基本并发性。该块中没有任何内容,为什么会这样做呢?
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) {}
}
}
}
答案 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毫秒)。不过,它不会再导致如此严格的倒退和倒退。