Java 带System.out.format和System.out.println的多线程
我在Oracle描述多线程场景中死锁的Java教程中遇到了这个问题 所以在这个例子中,我在第17行和第18行做了如下更改Java 带System.out.format和System.out.println的多线程,java,multithreading,deadlock,println,Java,Multithreading,Deadlock,Println,我在Oracle描述多线程场景中死锁的Java教程中遇到了这个问题 所以在这个例子中,我在第17行和第18行做了如下更改 public class DeadLock { static class Friend { private final String name; public Friend(String name) { this.name = name; } public String getName() { retur
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();
}
}
完成这些更改后,程序成功终止,不会导致死锁,并打印以下输出
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语句是如何防止死锁的?您在这里把事情搞混了 一段代码可能导致死锁的事实并不一定意味着每次代码运行时都会收到死锁 这是使多线程成为如此困难的主题的一个方面:如果您运行代码一次、10次或100次,并且一切都“正常”;下次仍有可能失败 换言之:尝试将代码放在最外层的循环中,迟早(可能更早;如果你不经常“睡眠”),你会遇到死锁
如果事情真的那么简单,死锁也能那么容易地被检测出来,我们就不需要那么多的书籍和库以及如何处理多线程的想法了。死锁根本不依赖于println函数。这是由于两个线程试图互相访问,并相互锁定造成的
从format到println的更改将在程序中引入足够的延迟,以允许线程相互锁定而不会发生冲突,即死锁。所以你还没有真正的修复它;您刚刚添加了一些延迟,这意味着线程不会死锁。无论是使用
System.out.print
还是System.out.format
,它们基本上都在做相同的事情
如果在Alphonse.bow(Gaston)
和bower.bowBack(Alphonse)
之间开始执行Gaston.bow(Alphonse)
,则会发生死锁:两个线程正在等待另一个线程持有的监视器,因此会发生死锁
这种情况的发生是不一致的,因为它取决于一个微妙的时间问题,取决于线程的调度方式-可能是Alphonse.bow
和bower.backbackback(Alphonse)
在执行Gaston.bow
之前完成,因此看起来没有死锁
解决此问题的经典方法是对锁获取进行排序,以便每次都首先获取相同锁的第一个锁;这样可以防止出现死锁:
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.
}
}
}
publicsvoidbow(friendbower){//方法不再同步。
int firstHash=System.identityHashCode(this);
int secondHash=System.identityHashCode(鲍尔);
Object firstMonitor=firstHash
(*)不能保证无死锁,因为System.identityHashCode
可以为不同的对象返回相同的值;但这不太可能
这是一个应用程序:如果你只有两个监视器,碰撞的可能性大约是10^-18;但是,如果你有>77k的监视器,冲突的可能性更大。为了用一些实际的证据来支持这里的其余答案,我在循环中运行了你的代码,它在100次尝试中死锁了82次,所以你的代码肯定仍然死锁。我看不出它会怎样
System.out.format
在锁定方面与System.out.println
没有什么不同。这没有什么区别——只是死锁取决于线程交错,这在运行之间是不同的。如果使用System.format多次运行,您可能会不时观察到正确的输出。使用println,您还将看到程序死锁的运行。确实是:第一个变体。@AndyTurner是否有可能是我做了这些更改而做错了什么?@Steve我认为您的解释是错误的;看看亚西莉亚的评论,我不同意。问题是“println语句是如何防止死锁的?”我的回答是它没有。我可以同意,它本身并不能作为一个答案,因为我提到的其他答案是有道理的;-)