2010-11-07 6 views
1

У меня очень странный тупик в приложении Java, который использует два потока. Оба потока считывают и записывают данные в общий хэш-файл. Чтобы избежать проблем синхронизации я сделал синхронизированы функции, чтения и записи данных в HashMap:Strange Deadlock (?)

private synchronized boolean identifiedLinksHasKey(String linkKey){ 
     return Parser.identifiedLinks.containsKey(linkKey); 
} 


private synchronized void putToIdentifiedLinks(String key, TreeSet<String> aset){  
     Parser.identifiedLinks.put(key,aset); 
} 

Однако программа висит в некоторой точке (что не происходит, когда я запустить его с одним потоком). Для отладки моего приложения я использовал jstack после того, как он висит, который дал мне следующую нить дампа:

"Thread-2" Прио = 6 TID = 0x0000000006b09800 нидь = 0x78fc работоспособных [0x00000000083ef000]
Java .lang.Thread.State: RUNNABLE по адресу java.util.HashMap.put (Неизвестный источник) по адресу bgp.parser.Entry. putToIdentifiedLinks (Entry.java:297) - заперта < 0x00000000853f2020> (а bgp.parser.Entry) в bgp.parser.Entry.parseTxtFile (Entry.java:141) в bgp.parser.Entry.run (Entry.java:31)

"тема-1" PRIO = 6 TID = 0x0000000006b52800 NID = 0x9390 работоспособный [0x00000000082ef000]
java.lang.Thread.State: Runnable в java.util.HashMap.getEntry (Неизвестно Источник) at java.util.HashMap.containsKey (Неизвестно Источник) at bgp.parse r.Entry. identifiedLinksHasKey (Entry.java:281) - заперта < 0x00000000853f00e0> (а bgp.parser.Entry) в bgp.parser.Entry.parseTxtFile (Entry.java:134) в bgp.parser.Entry.run (Entry.java:31)

Это швы, что два потока одновременно поддерживают две синхронизированные функции, что противоречит смыслу синхронизации. Такая же ситуация возникает, даже если я использую блокировки объектов. Хотя состояние потоков не BLOCKED, а RUNNABLE, они ведут себя как заблокированные, вероятно, потому, что они одновременно используют один и тот же хэш-файл.

Я был бы очень признателен, если бы кто-нибудь мог объяснить мне, почему эта странная ситуация случается.

+3

Это не тупик. Если он заблокирован, у вас есть другая проблема. –

+0

Это правда, я просто не знал, как это выразить. – Vasilis

ответ

3

«синхронизированное» ключевое слово блокируется на уровне объекта. То есть: два синхронизированных метода могут одновременно работать в одном объекте.

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

Редактировать: Повторное посещение трассировки стека, я все больше уверен, что это действительно так. Измените код следующим образом.

private boolean identifiedLinksHasKey(String linkKey){ 
     synchronized(Parser) { 
      return Parser.identifiedLinks.containsKey(linkKey); 
     } 
} 

private void putToIdentifiedLinks(String key, TreeSet<String> aset){  
    synchronized(Parser) {  
     Parser.identifiedLinks.put(key,aset); 
    } 
} 

Я не пробовал этот код сам, и я не уверен на 100%, можно ли использовать класс (Parser), а не объект, чтобы зафиксировать на. Если это не сработает, просто выберите любой (единственный) объект, доступный из обоих потоков/экземпляров.

+2

Используйте 'Parser.class' (уровень класса) или' Parser.identifiedLinks' (уровень объекта) для синхронизации, последний лучше всего в контексте данного imho. – rsp

+0

Спасибо за ответ. rsp уточнил это, и действительно Parser.identifiedLinks выполнил эту работу. Кажется, до сих пор я не знал правильного понимания замков. – Vasilis

0

Если Parser - это одноэлементный класс или статический член класса Entry, то синхронизация методов не будет работать, поскольку он защищает только переменные-члены объекта Entry. Статические члены не будут защищены этой схемой. Лучше всего сделать это, вероятно, для того, чтобы идентифицированный элементLinks класса Parser был ConcurrentHashMap.

7

сравнить эти два:

bgp.parser.Entry.putToIdentifiedLinks(Entry.java:297) - locked <0x00000000853f2020>
bgp.parser.Entry.identifiedLinksHasKey(Entry.java:281) - locked <0x00000000853f00e0>

Они держат другую блокировку. synchronized ключевое слово блокировка объекта пример. (То есть, если вы создаете два объекта Object a=new Object();Object b=new Object();, запирая в a не повлияет b)

+0

+1, это была моя ошибка. Я просто принял решение TumbleCow, потому что он был немного более подробным. – Vasilis

1

Я подозреваю, что identifiedLinksHasKey() и putToIdentifiedLinks() методы выполняется двумя различными экземплярами bgp.parser.Entry класса, в этом случае synchronized не будет работать.

0

Не могли бы вы задействовать файлы как объекты с гарантированным уникальным идентификатором? Если вы полагаетесь на это, скажем, вы ожидаете, что объект, представляющий файл, будет глобально уникальным в памяти. Он будет работать до тех пор, пока не будет нарушена унификация.

Нарушение в uniqness может происходить из API операционной системы. Он известен для Windows (но редко понимается людьми из Unix, например), этот дескриптор файла созданного файла - это не тот же дескриптор файла, который только что найден и открыт с помощью findFirst/findnext.

Рассмотрите файл API в операционной системе как API-интерфейс связи для очень удаленной системы без гарантии причины и следствия. Если вы создаете файл, это не значит, что вы можете сразу найти его, если вы удалите файл, это может означать, что вы, возможно, все еще найдете его впоследствии. и т.д.