2015-02-18 6 views
0

Я пытаюсь использовать объект String в качестве блокировки (да, я знаю, что это не рекомендуется - это только для понимания блокировок).synchronized зависит от инициализации строки

при инициализации блокировки при его создании, все работает хорошо:

код:

public class Action{ 

    String lock = new String("hello"); 

    @Override 
    public String myAction(long threadId){ 

     synchronized (lock) { 
      i++; 
      printToLog("thread " + threadId); 

      try { 
       Thread.sleep(100000); 
      } catch (InterruptedException e) { 
       printToLog("Thread "+threadId+ " could not sleep "+ e.getMessage() + "\n"); 
      } 
      printToLog("Thread "+threadId+ " slept well! "); 
     } 
     return i+""; 
    } 

    private void printToLog(String messege) { 
     DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
     //get current date time with Date() 
     Date date = new Date(System.currentTimeMillis()); 
     logger.info(messege + " at time: "+dateFormat.format(date)); 
    } 

} 

журналы:

[нить 555 на время: 2015/02/18 18: 16:03]
[Thread 555 хорошо спал! во время: 2015/02/18 18:17:43]
[thread 557 at time: 2015/02/18 18:17:43]
[Thread 557 спал хорошо! во время: 2015/02/18 18:19:23]
[thread 556 at time: 2015/02/18 18:19:23]
[Thread 556 хорошо спал! во время: 2015/02/18 18:21:03]

но когда я инициализирую блокировку члена экземпляра в методе, это как если синхронизация не работает.

код:

public class Action{ 

    String lock; 

    @Override 
    public String myAction(long threadId){ 
     lock = new String("hello"); 
     synchronized (lock) { 
      i++; 
      printToLog("thread " + threadId); 

      try { 
       Thread.sleep(100000); 
      } catch (InterruptedException e) { 
       printToLog("Thread "+threadId+ " could not sleep "+ e.getMessage() + "\n"); 
      } 
      printToLog("Thread "+threadId+ " slept well! "); 
     } 
     return i+""; 
    } 

    private void printToLog(String messege) { 
     DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
     //get current date time with Date() 
     Date date = new Date(System.currentTimeMillis()); 
     logger.info(messege + " at time: "+dateFormat.format(date)); 
    } 

} 

журналы:

[нить 555 на время: 2015/02/18 19:17:35]
[нить 556 на время: 2015/02/18 19:17:40]
[thread 556 at time: 2015/02/18 19:17:41]
[thread 557 at time: 2015/02/18 19:17:44]
[thread 560 на момент: 2015/02/18 19:17:48]
[Thread 555 хорошо спал! во время: 2015/02/18 19:19:15]
[Thread 556 спал хорошо! во время: 2015/02/18 19:19:20]
[Thread 556 хорошо спал! во время: 2015/02/18 19:19:21]
[Thread 557 спал хорошо! во время: 2015/02/18 19:19:24]
[Thread 560 хорошо спал! во время: 2015/02/18 19:19:28]

Я не понимаю, что такое меттер, где я начинаю объект? more - это строковый объект, так что в любом случае это не должно быть одной и той же ссылкой? что я скучаю?

Edit: Да, я случайно поменять код .. это то, что происходит, когда вы получаете «ваш пост, как представляется, содержат код, который не правильно отформатированный в качестве кода» слишком много раз, а затем выяснить, это было связано войти линии: | зафиксирует своп.

+0

Что вы подразумеваете под «когда я инициализирую метод». Можете ли вы опубликовать код, который создает и запускает потоки для этих двух случаев? – CKing

+1

В вашем первом примере ваш метод 'myAction' создает каждый раз отдельный объект блокировки, поэтому я не останавливаю использование других потоков, так как при использовании этого метода у всех из них будут новые блокировки. Во втором случае только один поток сможет ввести синхронизированный блок, потому что будет существовать только одна блокировка, созданная до вызова метода. Другими словами, вы можете удалить механизм блокировки и синхронизации из первого примера кода, и вы должны иметь одинаковые результаты. – Pshemo

+1

@Moria: вы случайно - замените два фрагмента кода? –

ответ

3

(вы, вероятно, поменяли фрагменты кода).

Я думаю, что вам не хватает важного аспекта Java synchronization. Вы не используете поле lockв качестве блокировки, вы назначаете замок экземпляру.Или, как сказано в руководстве:

В отличии от синхронизированных методов, синхронизированные заявления необходимо указать объект, который обеспечивает внутреннюю блокировку

Так что происходит в вашем втором (первом в фрагменте вопроса коды) является то, что создать новый объект, а именно:

lock = new String("hello"); 

И тогда вы фиксируете на этом объекте. Это означает, что каждый поток имеет другой экземпляр, на котором он блокируется. И поэтому синхронизации вообще нет.

Пример: у вас есть две темы t1 и t2. Сначала мы запускаем часть потока 1. Thread one вызывает метод и создает экземпляр String со значением "hello". Таким образом, память выглядит следующим образом:

+------+     +---------------+ 
|Action| <------------------+ thread memory | 
+------+  +-------+  +---------------+ 
| lock------->|String |  
+------+  +-------+ 
       |"hello"| 
       +-------+ 

Далее вы фиксируете на этом объекте, поэтому - отметил lock с &, вы получите:

+------+     +---------------+ 
|Action| <------------------+ thread memory | 
+------+  +-------+  +---------------+ 
| lock------->|String | &  
+------+  +-------+ 
       |"hello"| 
       +-------+ 

Теперь нить t2 приходит И первое, что t2 делает. создает новый объект:

+------+     +----------------+ 
|Action| <------------------+ thread2 memory | (old object) 
+------+  +-------+  +----------------+ +-------+ 
| lock------->|String |       |String | & 
+------+  +-------+       +-------+ 
       |"hello"|       |"hello"| 
       +-------+       +-------+ 

Так новый объект не заблокирован, и нить t2 может продолжить выполнение.


Возможно, что вы код действительно будет заблокирован. Например, возможно, что поток t1 может сначала создать объект, затем установить поле Action, а затем приостановить его. Затем t2 становится активным, также создает объект, устанавливает поле Action's, и поэтому оба потока заканчиваются тем же объектом, но это маловероятно.


Последнее замечание в том, что не существует никаких проблем с использованием «String как замок». Прежде всего, вы не используете String как блокировку, вы должны увидеть это как «блокировку» строки. Таким образом, виртуальная машина просто прикрепляет информацию к объекту, который заблокирован. Таким образом, нет good или bad объектов, которые нужно заблокировать.

+0

Но я не понимаю: 1) Какое это имеет значение, где я начинаю? член не является статическим, и в обоих случаях t1 и t2 будут иметь каждую «свою» блокировку. 2) как может быть, что каждая из них имеет другую строку? если они используют одно и то же строковое значение, его следует отнести к одному и тому же объекту в памяти - не так ли? благодаря! – Moria

+0

Дело в том, что вы ** создаете экземпляр нового объекта каждый раз, когда вы вызываете метод **. Поэтому вместо того, чтобы один объект был общим для всех потоков, каждый поток генерирует свой собственный объект. –

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