如何在Java中同步工作

首先, 这是一个示例 :

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) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); 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() { public void run() { alphonse.bow(gaston); } }).start(); new Thread(new Runnable() { public void run() { gaston.bow(alphonse); } }).start(); } } 

我得不到的是堵塞的发生。 主函数启动两个线程,每个线程开始自己的弓。

什么是“同步”块? 为同一个对象运行同样的function(正如我原来的想法)? 同一个类的所有对象的相同的function? 同一个对象的所有同步函数? 同一类的所有对象的所有同步函数?

帮帮我。

在Java中,每个Object提供了一个线程synchronize或locking的能力。 当一个方法被同步时,该方法使用它的对象实例作为锁。 在你的例子中,方法bowbowBacksynchronized ,并且都在同一个class级Friend 。 这意味着执行这些方法的任何线程都将在Friend实例上同步它的锁。

导致死锁的一系列事件是:

  1. 第一个线程开始调用alphonse.bow(gaston) ,它在alphonse Friend对象上synchronized 。 这意味着线程必须从这个对象获取锁。
  2. 第二个线程开始调用gaston.bow(alphonse) ,它在gaston Friend对象上synchronized 。 这意味着线程必须从这个对象获取锁。
  3. 现在开始的第一个线程调用了bowback并等待gaston上的锁被释放。
  4. 现在开始的第二个线程调用bowback并等待alphonse上的锁被释放。

要更详细地显示事件的顺序:

  1. main()开始在主Therad中执行(称之为Thread#1),创build两个Friend实例。 到现在为止还挺好。
  2. 主线程使用代码new Thread(new Runnable() { ... Thread#2调用alphonse.bow(gaston) ,它在alphonse Friend对象上synchronized来启动它的第一个新线程(称为线程2)。线程#2因此获得了对于alphonse对象的“locking”并进入了bow法。
  3. 时间片发生在这里,原来的线程有机会做更多的处理。
  4. 主线程开始第二个新线程(称为线程#3),就像第一个线程一样。 线程#3调用gaston.bow(alphonse) ,它在gaston Friend对象上同步。 由于没有人获得gaston对象实例的“locking”,所以线程#3成功获取该锁并进入bow方法。
  5. 时间片发生在这里,线程#2有机会做更多的处理。
  6. 线程#2现在调用bower.bowBack(this);bowergaston的例子的gaston 。 这是gaston.bowBack(alphonse)的调用的逻辑等价物。 因此,这个方法在gaston实例上是synchronized的。 该对象的锁已经被获取,并被另一个线程(线程#3)保存。 因此,线程#2必须等待gaston上的锁被释放。 线程处于等待状态,允许线程3进一步执行。
  7. 线程#3现在调用bowback ,在这种情况下在逻辑上与调用alphonse.bowBack(gaston) 。 为此,需要获取alphonse实例的锁,但该锁由Thread#2保存。 此线程现在处于等待状态。

而你现在处于一个线程无法执行的位置。 线程#2和线程#3正在等待一个锁被释放。 但是没有一个线程正在进行,这两个锁都不能被释放。 但是,没有一个锁被释放,任何线程都不能取得进展。

因此:僵局!

死锁通常取决于事件发生的特定顺序,由于难以重现,可能难以debugging。

同步有两个作用 :

  • 首先,同一个对象上的两个同步方法的调用是不可能交错的。 当一个线程正在执行一个对象的同步方法时,所有其他调用同一对象的同步方法的线程将阻塞(挂起执行),直到第一个线程完成对象。
  • 其次,当一个同步的方法退出时,它会自动build立一个与先前同步对象的任何后续调用同步方法的before-before关系。 这保证了对所有线程都可见的对象状态的改变。

简而言之,它会阻止对同一个对象的同步方法的任何调用。

同一个对象的所有同步函数。 标记一个方法“synchronized”与在方法的整个内容中放置一个“synchronized(this){”方块非常相似。 我不说“相同”的原因是因为我不知道编译器是否发出相同的字节码,但AFAIK定义的运行时效果是相同的。

死锁是一个经典的locking反转。 一个线程lockingalphonse。 然后(或同时在多核系统上)另一个线程lockinggaston。 这部分要求线程的调度恰好在正确的点交错。

然后,每个线程(以任何顺序或同时)尝试获取已由另一个线程保持的锁,从而每个线程都进入hibernate状态。 直到另一个释放它的锁,它们都不会唤醒,但是直到唤醒(或终止)它们都不会释放它的锁。

synchronized方法和把所有这些方法的代码封装成一样

 synchronized(this) { /// code here ... } 

块。

对于给定的对象实例o ,一次只有一个线程可以运行任何同步的(o)块。 每一个其他的线程都会试图嚎,大哭,直到运行该块的线程(具有同步的锁 )退出该块(放弃锁)。

在你的情况下,当Alphonse开始在线程1中鞠躬时,发生死锁,从而进入同步块。 线程1然后被系统交换出去,所以线程2可以启动,让Gaston鞠躬。 但加斯顿还不能回头,因为它在阿尔方斯上同步,而线程1已经有了这个锁。 它将因此等待线程1离开该块。 系统然后将交换线程1,这将尝试让Alphonse回头。 除了不能这样做,因为线程2在Gaston上有同步locking。 这两个线程现在都卡住了,等待另一个完成鞠躬,才能够回头…