2008-12-08 5 views
5

I user sun jdk 1.5 ThreadPoolExecutor (24, 24,60, TimeUnit.SECONDS, новый LinkedBlockingQueue()). soemtime Я использую JDB инструмент для определения состояния всех потоков в пул потоков являются «ожидание в монитор», код:deadlock on synchronized (String intern())

String key = getKey(dt.getPrefix(), id); 
    synchronized (key.intern()) {  -----> 

Есть проблема в «синхронизированного (key.intern())»?


Я получаю следующее informatnio используя JDB инструмент, состояние 24 нитей «ждет в монитор», это означает, что 24 нити затор на «key.intern()».

(java.lang.Thread) 0x28 бассейн-3-нить-2 ожидания в мониторе

(java.lang.Thread) 0x27 бассейн-3-нить 3-ожидания в мониторе

(java.lang.Thread) 0x1b бассейн-3-нить 4-ожидания в мониторе

(java.lang.Thread) 0x1a бассейн-3-нить 5-ожидания в мониторе

(java.lang .Thread) 0x19 пул-3-нить-6, ожидающий на мониторе

(java.lang.Thread) 0x18 бассейн-3-нитка-7 ожидания в мониторе

(java.lang.Thread) 0x17 бассейн-3-нитка-8 ждет в мониторе ...

, поэтому результат: в среде с несколькими потоками, метод Sting intern() может быть тупиковым, ок?

+0

Первым вопросом является то, что вы хотите достичь? В чем проблема? Зачем вам синхронизировать? – 2008-12-08 11:27:10

+0

Вы смотрели темы OUTSIDE the threadpool, чтобы посмотреть, ждут ли они на мониторе? Вы должны обратить внимание на точный объект, который также синхронизируется с каждым потоком. – 2008-12-08 17:08:11

+0

На мониторе есть две темы, выходящие за пределы потока, а также отслеживают одну и ту же строку (key.intern()). – user44230 2008-12-12 03:11:21

ответ

4

Довольно. Проблема в том, что key.intern() на самом деле не уникален, потому что возвращает строку из пула. String.intern() может возвращать тот же объект даже при использовании на разных объектах. Попробуйте использовать сам key или другой объект.

-1

key.intern() гарантия уникальности, потому что key.intern() возвращает строку из пула констант String.

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#intern() стажер

общественности Строка стажер() Возвращает каноническое представление для строкового объекта. Пул строк, первоначально пустой, поддерживается конфиденциально классом String.

-1

String.intern() - это родной метод - это может быть причиной проблемы.

+0

Зачем это проблема? Я думаю, что тот факт, что метод является родным или нет, не имеет никакого влияния, он возникает до начала синхронизации. – 2011-07-12 18:24:19

1

Как говорит Бомбе, key.intern() не обязательно даст вам уникальный ключ для синхронизации.

Однако вы должны быть осторожны при изменении кода. Прежде чем изменять его, вам нужно понять стратегию блокировки. Удаление вызова intern() может дать вам код, который работает правильно, но содержит гонку данных, которая вас укусит позже.

2

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

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

Пересмотреть, что нужно синхронизировать.

2

Если вам нужно синхронизировать строку, не используйте экземпляр String в качестве мьютекса (интернированный или нет). Строка может быть использована для создания хорошего объекта мьютекса: synchronizing on an ID.

2

У вас возникли две проблемы. В качестве блокировки используется String. Второй - тупик.

Если вы используете String как блокировку, вы потеряете контроль над «who» и «where», который примет этот объект.

Ваша проблема с блокировкой, которая может быть вызвана или не вызвана блокировкой строки. Однако фактическая причина тупика: «Ваш код может привести к тупику». Если это произойдет, это произойдет.

Вы должны отслеживать стеки ваших потоков, чтобы разрешить взаимоблокировки.

5

Я отправил соответствующий вопрос в этот раз, что вы можете захотеть взглянуть на: Problem with synchronizing on String objects?

Что я узнал: с помощью intern'ed Струны для синхронизации является плохого практика.

2

Здесь недостаточно кода, чтобы сообщить, что происходит не так. Это может быть узким местом, как уже упоминалось, но, по крайней мере, один поток должен работать (с довольно интенсивным использованием ЦП), чтобы это произошло, или поток, в котором заблокирован замок, отключается, не отпуская блокировку.

Тупик - это еще одна возможность, но для синхронизации потребуется два отдельных замка на нескольких потоках, и здесь вы указали только один объект блокировки.

Это невозможно определить без дополнительной информации.

1

У вас, скорее всего, есть тупик.

Если вы хотите избежать взаимоблокировок, каждая нить должна всегда приобретать блокировки в том же порядке. Когда вы используете String.intern() для получения ваших блокировок, вы блокируете экземпляр, к которому имеет доступ любой код во всей JVM, и блокировка. Скорее всего, другие потоки в вашем собственном коде блокируют, но это не обязательно.

Я не уверен, что вы подразумеваете в своем ответе на «ключ.intern(), гарантирующий уникальность». Метод intern()уменьшает уникальность, возвращая тот же объект для каждой строки, эквивалентной.

String s1 = new String(new char[] { 'c', 'o', 'm', 'm', 'o', 'n' }).intern(); 
    String s2 = new String("commo" + (s1.charAt(s1.length() - 1)).intern(); 
    String s3 = "common"; 
    if ((s1 == s2) && (s1 == s3)) 
    System.out.println("There's only one object here."); 

Код выше будет показано, что даже если вы создали два уникальных экземпляров, по интернирование их, заменив их единой канонической инстанции.

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

0

Как насчет использования уникального строкового префикса со значением блокировки и использованием String.intern() в синхронизированном блоке. Например, если вы хотите заблокировать строку «lock1», используйте префикс UUID следующим образом: «85e565b3-d440-46e7-93b6-69ee7e9a63ee-lock1». Этот тип строки не должен быть уже в основном пуле. то есть вероятность блокировки другим кодом очень низкая.