2016-08-20 4 views
0

Я считаю, это простой вопрос, но все же я не получаю его самостоятельно. Скажем, у меня есть следующий код.порядок вызова синхронных методов

Runnable objectRunnable = new Runnable() { 
    void run() { 
      synchronized(object) { 
       for (int i = 0; i < 5; i++) { 
        System.out.println("it's runnable"); 
        Thread.sleep(100); 
       } 
      } 
    } 
}; 

void doSomething() { 
    synchronized(object) { 
     for (int i = 0; i < 5; i++) { 
      System.out.println("it's doSomething"); 
      Thread.sleep(100); 
     } 
    } 
} 

synchronized (object) { 
    new Thread(objectRunnable).start(); 
} 
object.doSomething(); 

Таким образом, выход как

it's doSomething 
it's doSomething 
it's doSomething 
it's doSomething 
it's doSomething 
it's runnable 
it's runnable 
it's runnable 
it's runnable 
it's runnable 

Вопрос почему doSomething() идет перед нитью? Более того, если я поместил несколько вызовов методов объекта после блока синхронизации, все они будут вызваны впоследствии, и только тогда программа вернется к содержимому потока. Если я заменю эту линию вызова потока в синхронизирующем блоке, например, вызывая некоторый метод аналогового объекта, чем все в порядке и идет в указанном порядке.

Существуют ли у методов синхронизированного объекта какой-то приоритет в выполнении перед любыми потоками, синхронизированными на этом объекте?

+0

Этот код не компилируется, к сожалению. – tkausl

ответ

1

У вас здесь есть состояние гонки: ваш runnable блокируется, ожидая на мониторе при запуске из-за synchronized (object) вокруг его создания. Когда поток, создающий runnable, освобождает монитор, вновь созданный поток с runnable не получает возможности его захватить, потому что тот же поток снова вводит его в метод doSomething().

Если добавить вызов Thread.sleep(100); перед вызовом object.doSomething()

synchronized (object) { 
    new Thread(objectRunnable).start(); 
} 
Thread.sleep(100); // <<== Add this line 
object.doSomething(); 

порядок распечатки будет обратной (demo).

it's runnable 
it's runnable 
it's runnable 
it's runnable 
it's runnable 
it's doSomething 
it's doSomething 
it's doSomething 
it's doSomething 
it's doSomething 
+0

немного очищает, но все же, почему же после сиронического создания runnables потоки не называются далее? мне кажется логичным, что, поскольку мы называем 'start()' на этом потоке в коде, и он идет до 'doSomething()', они должны быть помещены как на вершину стека вызываемых методов, а не пропускать текущий поток захватить монитор перед ними – idementia

+0

@idementia Тема начинается, но сразу же блокируется, потому что родительский поток все еще удерживает блокировку. Как только родительский поток освобождает блокировку, он предназначен для захватов, но тот же поток, по-видимому, ближе к захвату, потому что он уже запущен, а другой поток заблокирован. – dasblinkenlight

2

Потому что основной поток является первым, чтобы получить замок. Возможно, это был порожденный поток, вы просто не можете быть уверены, хотя это гораздо менее вероятно, потому что требуется некоторое время после вызова start(), чтобы поток фактически начал работать.

Что касается остальной части вашего вопроса, это слишком расплывчато, чтобы получить ответ.

Смежные вопросы