使用System.out.format和System.out.println进行多线程 [英] Mutithreading with System.out.format and System.out.println
问题描述
我在Oracle Java教程中遇到了示例多线程方案中的死锁.
I came across this example on Oracle's Java Tutorial describing Deadlock in multi threading scenarios.
因此,在此示例中,我在第17行和第18行进行了以下更改.
So in this example I made following change at line 17 and line 18.
public class DeadLock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
//My Changes
//System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName()); //Line 17
System.out.println(this.name + ": " + bower.getName() + " has bowed to me!"); //Line 18
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend alphonse = new Friend("Alphonse");
final Friend gaston = new Friend("Gaston");
new Thread(new Runnable() {
@Override
public void run() {
alphonse.bow(gaston);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
gaston.bow(alphonse);
}
}).start();
}
}
进行这些更改后,程序将成功终止,而不会导致死锁,并在输出后进行打印
Upon doing these changes the program terminated successfully without causing deadlock and printed following output
Alphonse: Gaston has bowed to me!
Gaston: Alphonse has bowed back to me!
Gaston: Alphonse has bowed to me!
Alphonse: Gaston has bowed back to me!
所以我的问题是-为什么会这样表现? println语句如何防止死锁?
So my question is- why did it behave like this? How did the println statement prevent the deadlock?
推荐答案
使用System.out.print
还是System.out.format
并没有什么不同:它们基本上是在做相同的事情.
There is no difference in whether you use System.out.print
or System.out.format
: they're basically doing the same thing.
如果在Alphonse.bow(Gaston)
和bower.bowBack(Alphonse)
的开始之间开始执行Gaston.bow(Alphonse)
,则在这里发生死锁(反之亦然):两个线程正在等待另一个线程持有的监视器,因此发生死锁.
The deadlock occurs here if execution of Gaston.bow(Alphonse)
is started between the start of Alphonse.bow(Gaston)
and bower.bowBack(Alphonse)
(or vice versa): the two threads are waiting for a monitor held by the other, and thus deadlock occurs.
这种情况不一致地发生,因为它取决于细微的计时问题,具体取决于线程的调度方式-Alphonse.bow
和bower.backBack(Alphonse)
可能在执行Gaston.bow
之前完成,因此看起来好像没有僵局.
This happens inconsistently, because it depends upon a subtle timing issue, depending upon how the threads are scheduled - it is possible that Alphonse.bow
and bower.backBack(Alphonse)
complete before Gaston.bow
is executed, so it looks like there is no deadlock.
解决此问题的经典方法是对锁获取进行排序,以便第一个相同的锁每次都首先获取;这样可以避免出现死锁的情况:
The classic way to fix this is to order the lock acquisition, so that the first the same lock is acquired first every time; this prevents the possibility of deadlock:
public void bow(Friend bower) { // Method no longer synchronized.
int firstHash = System.identityHashCode(this);
int secondHash = System.identityHashCode(bower);
Object firstMonitor = firstHash < secondHash ? this : bower;
Object secondMonitor = firstHash < secondHash ? bower : this;
synchronized (firstMonitor) {
synchronized (secondMonitor) {
// Code free (*) of deadlocks, with respect to this and bower at least.
}
}
}
(*)并非相当保证没有死锁,因为System.identityHashCode
可以为不同的对象返回相同的值.但这不太可能.
(*) It's not quite guaranteed to be deadlock free, since System.identityHashCode
can return the same value for distinct objects; but that's reasonably unlikely.
它是生日悖论的应用:如果您只有两个显示器,发生碰撞的几率约为10 ^ -18;但是如果您有超过77,000台显示器,则很可能发生碰撞.
It's an application of the Birthday paradox: if you've got just two monitors, the chance of collision is something like 10^-18; but if you've got >77k monitors, a collision is more likely than not.
这篇关于使用System.out.format和System.out.println进行多线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!