JAVA: Какую часть блока кода синхронизирует блок ключевых слов? и объяснить этот тупик

1

У меня есть вопросы:
1. Какая часть кода синхронизированного метода, блок синхронизации?
например:

public class example{

  public synchronized void f1(){
    //some code....
     f2();
    }
    public synchronized void f2()
    {
      //some code...
    }
}
public void main(String[[] args)
{
   Thread t1 = new Thread(new Runnable()
   {public void run(){f1();)},
          t2 = new Thread(new Runnable()
   {public void run(){f2();};
   t1.start();
   t2.start();

}

поэтому после запуска t1 t2 не может запускаться - потому что он ждет t1. Но что t1 начинает делать f2, означает ли это, что t2 может войти в f1?

И если вы можете, пожалуйста, объясните этот пример тупика. я не понял. источник: http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

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();
    }
}
  • 0
    из 2-х вопросов первый неясен (не компилируется, сложно сказать, что вы хотите), на вопрос о примере с поклоном уже дан ответ.
  • 0
    так когда alphonse.bow(gaston); активирован, alphonse заблокирован в его функции bow() и не может делать ничего другого (например, bowBack() ), пока он не выйдет из функции bow() ?
Показать ещё 2 комментария
Теги:
multithreading
deadlock

2 ответа

1
Лучший ответ

synchronized метод в Java блокирует весь метод, и, что немаловажно, он блокирует экземпляр объекта, на который вызывается метод. Это означает, что два синхронизированных метода в одном и том же объекте имеют одну и ту же блокировку и поэтому не могут одновременно выполняться разными потоками.

Например, в классе ниже

public class myClass
{
  synchronized void method1()
  {

  }

  synchronized void method2()
  {

  }
}

method1() и method2() никогда нельзя вызывать одновременно на одном и том же объекте, поскольку код достаточно эквивалентен:

public class myClass
{
  void method1()
  {
    synchronized(this)
    {
      // ...
    }
  }

  void method2()
  {
    synchronized(this)
    {
      // ...
    }
  }
}

Если вы хотите, чтобы оба метода были независимо синхронизированы на разных блокировках, вы можете сделать что-то вроде следующего:

public class myClass
{
  private final Object method1Lock = new Object();
  private final Object method2Lock = new Object();

  void method1()
  {
    synchronized(method1Lock)
    {
      // ...
    }
  }

  void method2()
  {
    synchronized(method2Lock)
    {
      // ...
    }
  }
}
0

Пример взаимоблокировки: поскольку два потока (выполняющие экземпляр процесса или даже легкие процессы, как их называют некоторые операционные системы) получают один и тот же замок, один из которых всегда получает блокировку, а другой должен ждать, пока тот, который приобрел блокировку сначала (это определяется JVM, думайте о JVM как о операционной системе - кто-то должен гарантировать атомарность блокировки, то есть до JVM). В примере один поток будет выполнять лук(), за которым следует bowBack(), но к тому времени, когда выполняется битBack(), другой поток выполнил покупку в той же блокировке (путем вызова лука()), оставив другой поток в состояние ожидания, которое зависит от первого потока и первого потока, зависит от одной и той же блокировки при вызове функции bowBack() - произошла циклическая зависимость, то есть в тупике.

из документа оракула:

Во-первых, невозможно, чтобы две вызовы синхронизированных методов на одном объекте чередовали. Когда один поток выполняет синхронизированный метод для объекта, все другие потоки, которые вызывают синхронизированные методы для одного и того же блока объектов (приостанавливают выполнение) до тех пор, пока первый поток не будет выполнен с объектом.

В следующем примере говорится, что его чрезвычайно вероятно, что произойдет тупик, подразумевая, что это не обязательно должно произойти. Это связано с тем, что первый поток, который получил блокировку, может завершить выполнение функции bowBack(), прежде чем второй поток получит блокировку, то есть вызовы bow() (я использую метод lock как терминологию из теории операционной системы, которая придумала исходный язык для это один раз), именно JVM может решить, какой поток может выполняться в какое время (фактическое планирование нитей, выполняющих схему, так сказать, и изменение исполнительного потока (называемого контекстным коммутатором) является довольно дорогостоящим, поэтому JVM может решите, чтобы первый поток выполнялся в течение более длительного периода, в результате чего не произошло тупик). Думая о планировании потоков, лучше всего рассматривать его как довольно случайную вещь, если это может произойти в тупик раньше или позже, один запуск программы (или другой вид цикла, например, метод, который порождает два потока, как в примере ) мог бы зайти в тупик, а другой - нет. Многопоточность - это много того, что нужно учитывать, что нужно блокировать, а не комбинировать блокировки таким образом, чтобы порождать тупик.

Может быть, вы должны попытаться заставить пример не заходить в тупик, например, спать один поток на некоторое время (например, попробуйте с 1 мс перед тем, как ввести лук, прежде чем скажите gaston.bow()) и посмотрите, что происходит, помните, что нет никаких гарантий, поэтому спать один поток на самом деле не делает поток кода безопасным, тупик будет возникать реже.

А как насчет того, чтобы ввести еще пару потоков, делающих лук() - действительно ли спал на самом деле помог, или просто отложить проблему....?

  • 0
    `Первый поток и первый поток зависят от одной и той же блокировки при вызове bowBack ()` Вы говорите, что bow () и bowBack () используют одну и ту же блокировку ?? это не имеет никакого смысла. почему две разные функции будут использовать одну и ту же блокировку?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню