如何在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();
    }
}

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

“同步”块究竟是什么? 运行同一个对象的相同功能(正如我原先所想的那样)? 同一个类的所有对象都具有相同的功能? 同一个对象的所有同步函数? 所有同一类的所有对象的同步函数?

在这里帮助我。


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

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

  • 第一个Thread开始调用alphonse.bow(gaston) ,它在alphonse Friend对象上synchronized 。 这意味着线程必须从这个对象获取锁。
  • 第二个线程开始调用gaston.bow(alphonse) ,它在gaston Friend对象上synchronized 。 这意味着线程必须从这个对象获取锁。
  • 现在开始的第一个线程会调用bowback并等待gaston上的锁定被释放。
  • 现在开始的第二个线程调用bowback并等待alphonse上的锁被释放。
  • 更详细地显示事件的顺序:

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

    因此:僵局!

    死锁通常取决于发生的特定事件顺序,这可能使得难以调试,因为它们很难重现。


    同步有两个作用:

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


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

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

    然后,每个线程(以任何顺序或同时)尝试获取已由另一线程保持的锁,并因此每个线程都进入休眠状态。 直到另一个释放它的锁,它们都不会唤醒,但它们都不会在它醒来(或终止)之前释放它的锁。

    链接地址: http://www.djcxy.com/p/16337.html

    上一篇: How does synchronized work in Java

    下一篇: Thread safety in Singleton