当前位置: 首页 > 面试题库 >

使用System.out.format和System.out.println进行多线程

谯英彦
2023-03-14
问题内容

我在Oracle
Java教程中遇到了这个示例,该示例描述了多线程场景中的死锁。

因此,在此示例中,我在第17行和第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();
  }
}

完成这些更改后,程序将成功终止,而不会导致死锁,并在输出后进行打印

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语句如何防止死锁?


问题答案:

无论您使用System.out.print还是,都没有什么区别System.out.format:它们基本上是在做同一件事。

如果Gaston.bow(Alphonse)Alphonse.bow(Gaston)和的开始之间开始执行,则在此处发生死锁bower.bowBack(Alphonse)(反之亦然):两个线程正在等待另一个线程持有的监视器,因此发生死锁。

出现这种情况不一致,因为它依赖于一个微妙的时机的问题,这取决于线程是如何安排-
这是可能的,Alphonse.bow并且bower.backBack(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.
    }
  }
}

(*)这不是 保证自由是僵局,因为System.identityHashCode可以换取不同的对象相同的值; 但这不太可能。

这是生日悖论的一种应用:如果只有两个监视器,则发生碰撞的机会约为10
^ -18;但是如果您的显示器> 77k,则很可能发生碰撞。



 类似资料:
  • 问题内容: 我有一个多线程Java应用程序,该应用程序会将有关它收到的消息的信息输出到控制台以进行调试。每次应用程序收到消息时,它将在消息上调用。 我遇到的问题是,如果应用程序被消息淹没,则会打印错误信息(例如旧缓冲区信息)。这使我想知道是否存在线程问题,即多个线程一次调用该函数,而没有正确刷新缓冲区。 在我的主程序(线程)中,我有以下效果: 在我的线程中,我有以下效果: 是否有一种简单的方法可以

  • 我构建了这个“节流”任务运行器,它在HashMap中收集一些数据,同时(每分钟)将数据“带走”并清除HashMap。在我的测试中,我注意到executor部分可以停止,并且永远不会再次清除HashMap。我假设这是因为我所做的HashMap修改不是线程安全的,它在内部崩溃,没有恢复。我正在两个线程中修改HashMap。有人能告诉我如何优化HashMap修改的正确方向吗。

  • 问题内容: 我可以选择让用户从FileChooser提交多个文件,以通过一些代码进行处理。结果将是读取文件的IO,然后是对存储数据的实际大量计算。允许用户选择多个文件,并且由于文件处理不依赖于所选的任何其他文件,因此使我的工作变得更加轻松。 此外,用户需要具有按钮列表,每个要取消的任务一个按钮以及“全部取消”按钮。因此,我必须考虑选择性或集体杀死一项或所有任务的能力。 最后一个要求是,我不允许用户

  • 本文向大家介绍C#使用Parallel类进行多线程编程实例,包括了C#使用Parallel类进行多线程编程实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#使用 Parallel 类进行多线程编程的方法。分享给大家供大家参考。具体如下: 希望本文所述对大家的C#程序设计有所帮助。

  • 本文向大家介绍C#多线程学习之(四)使用线程池进行多线程的自动管理,包括了C#多线程学习之(四)使用线程池进行多线程的自动管理的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#多线程学习之使用线程池进行多线程的自动管理。分享给大家供大家参考。具体如下: 在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应