Выгрузка потока, выполняющего синхронизированный метод - PullRequest
5 голосов
/ 25 мая 2011

Дайте следующий код

    class Test{
       double x;
       public void synchronized a()
       { 
          x = 0;
          //do some more stuff
       }
       public void b() 
       { 
          x = -1; 
       } 
    }

Может ли поток в () в середине модифицирования x быть вытеснен потоком, который вызывает b () для того же объекта?

Разве синхронизированный метод не выполняется как одна атомарная операция?

Я полагаю, что возможен другой путь (поток в b () может быть прерван потоком, который вызывает a () для того же объекта, поскольку b () не защищает мою блокировку объекта Test).

Может кто-нибудь пролить свет на это?

Ответы [ 2 ]

11 голосов
/ 25 мая 2011

synchronized только останавливает другие потоки от получения того же монитора. Это никак делает операцию атомарной. В частности:

  • Побочные эффекты метода могут наблюдаться другими потоками, которые не пытаются синхронизироваться на одном мониторе
  • Если возникает исключение, отката не происходит
  • Другие потоки могут получать доступ и изменять те же данные, которые используются синхронизированным методом, если они не синхронизированы на одном мониторе.

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

0 голосов
/ 25 мая 2011

Поскольку b() не синхронизирован, а a() - это возможно, один поток может находиться в a(), а другой - в b(). Таким образом, значение x наиболее вероятно будет искажено из-за параллельного несинхронизированного доступа к x.

Кроме того, если ваш код был таким:

class Test{
       double x;
       public void synchronized a()
       { 
          x = 0;
          //do some more stuff
       }
       public void b() 
       { 
          x = -1; 
          a(); //added call to a()
       } 
    }

и оба ваших потока работают на том же экземпляре , тогда возникает вероятность того, что поток 1 [в настоящее время в a() вытесняется потоком 2 [в настоящее время в b()].

Однако после прерывания потока 1, когда поток 2 пытается ввести метод a(), JVM не разрешит его; поскольку другой поток [хотя и не запущенный] уже имеет блокировку. Следовательно, теперь поток 2 будет вынужден ждать, пока поток 1 завершит выполнение a() и вернется. Тогда поток 2 [скорее всего] будет возвращен к жизни и разрешен к исполнению a().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...