2013-07-09 12 views
5

Próbuję zsynchronizować wypłatę pliku na twardym dysku z bazy danych.Próbuję zsynchronizować system zapisu plików w java

Co robię w celu sprawdzenia, czy plik istnieje, a jeśli nie, to pobrać plik z bazy danych i wdrożyć go. Nie chciałbym pisać tego pliku wiele razy z powodu stanu Race.

Oto kod zrobiłem:

importent: Ten kod jest wewnątrz Bean ze wszystkimi jego znaczeń

@Override 
public String getThumbnailPictureUrl(Design design) { 
    String relativePath = String.format(THUMBNAIL_URL, design.getId(), design.getThumbnailPicture().getFileName()); 
    String realPath = servletContext.getRealPath("/"+relativePath); 
    logger.info("Request Thumbnail picture for design: " + design.getId()); 
    logger.info("Thumbnail picture relative path: " + relativePath); 
    logger.info("Thumbnail picture real path: " + realPath);   
    File file = new File(realPath); 
    if(!file.exists()) 
    { 
     synchronized (thumbnailLock) 
     { 
      if(!file.exists()) 
      { 
      logger.warn("Could not fild file in path: " + realPath); 
      FileAttachment pictureAttachment = design.getThumbnailPicture(); 
      Hibernate.initialize(pictureAttachment.getAttachment()); 
      Data data = (Data) pictureAttachment.getAttachment(); 
      file = toolBox.convertBlobToFile(data.getBlob(), file); 
      logger.warn("file created in path: " + realPath); 
      } 
     } 
    } 
    return relativePath; 
} 

Dzięki takiemu rozwiązaniu w przypadku nie znajdę plik, który naprawdę nie będę zapisywał pliku 2 razy, jak również jakikolwiek inny plik, ponieważ synchronizuję cały blok dla wszystkich wątków próbujących go osiągnąć, nawet jeśli mam napisać inny plik.

Wszelkie sugestie?

Dzięki.

+1

Jaką wersję Java? – erickson

Odpowiedz

1

A co z tworzeniem zamków w postaci HashMap? Klucz będzie ścieżką pliku, a wartość będzie tylko obiektem używanym jako blokada. Powiedzmy, że ta mapa jest zdefiniowany następująco:

Map<String, Object> locks = new Map<String, Object>(); 

A to zastosowanie:

if(!file.exists()) 
{ 
    Object lock = null; 
    synchronized (locks) { 
     lock = locks.get(file.getName()); 
     if(lock == null) { 
      lock = new Object(); 
      locks.put(file.getName(), lock); 

     } 
    } 
    synchronized (lock) 
    { 
     if(!file.exists()) 
     { 
     logger.warn("Could not fild file in path: " + realPath); 
     FileAttachment pictureAttachment = design.getThumbnailPicture(); 
     Hibernate.initialize(pictureAttachment.getAttachment()); 
     Data data = (Data) pictureAttachment.getAttachment(); 
     file = toolBox.convertBlobToFile(data.getBlob(), file); 
     logger.warn("file created in path: " + realPath); 
     } 
    } 
    synchronized(locks) { 
     map.remove(lock)); 
    } 
} 
+0

Ścieżki plików są dynamiczne. Nie mogę utworzyć klucza/obiektu w locie i zablokować go ... ma ten sam potencjał warunku wyścigowego. do czasu, kiedy zablokuję obiekt, następny wątek zastąpi go nowym. – Gleeb

+0

Spójrz na mój kod, myślę, że rozwiązuje wszystkie warunki wyścigu. Przynajmniej te, o których mogłem pomyśleć. – Avi

+0

Nadal czeka na wszystkie pliki. Ale oryginalna sekcja krytyczna jest zablokowana dla każdego pliku. Operacje tabelowe 'locks' nie są zbyt kosztowne (w przetwarzaniu czasu). – Avi

5

podobne do @ rozwiązanie avi, ale stosując ConcurrentHashMap.

private final ConcurrentMap<String, Object> map = new ConcurrentHashMap<>(); 

String name = file.getName(); 
Object lock = map.get(name); 
if (lock == null) { 
    map.putIfAbsent(name, new Object()); 
    lock = map.get(name); 
} 

synchronized (lock) { 
    // do something 
} 

map.remove(name); 
+0

Twoje rozwiązanie tworzy nowy obiekt za każdym razem, gdy kwerenda o plik jest sprawdzana, więc nie zawsze jest lepsze niż rozwiązanie @ Avi. –

Powiązane problemy