2012-12-06 16 views
9

Jedną ze strategii unikania zakleszczeń w Java Wielowątkowość jest używanie limitu czasu. Załóżmy, że jeden wątek uzyskał blokadę jednego zasobu i oczekuje na blokadę innego zasobu. Po pewnym czasie, jeśli nie może uzyskać blokady na zasobie 2, powinien przestać czekać na blokadę zasobu2. Powinien także zwolnić blokadę zasobu1. W ten sposób uniknie się zakleszczeń.Korzystanie z limitu czasu w celu uniknięcia zakleszczenia w wielowątkowość Java

Ale jak zaimplementować go w Javie? Jak jawnie "zwolnić" blokadę? Jak zdefiniować limit czasu oczekiwania na blokadę.

Co to są dokładne polecenia i składnia java. Czy jest jakiś przykład z pogranicza światów?

+2

Inne rozwiązania; zawsze nabywaj zamki w tej samej kolejności lub nigdy nie zdobądź więcej niż jednego zamka. ;) –

+0

+1 dla 'Jak zdefiniować limit czasu oczekiwania na blokadę' – n611x007

Odpowiedz

8

Oto zmyślony przykład z 2 zamkami i 2 wątków, które próbują zdobyć je w różnej kolejności. Bez przekroczenia limitu czasu kod zakleszczyłby się.

public static void main(String[] args) throws Exception { 
    final ReentrantLock lock1 = new ReentrantLock(); 
    final ReentrantLock lock2 = new ReentrantLock(); 
    Runnable try1_2 = getRunnable(lock1, "lock 1", lock2, "lock 2"); 
    Runnable try2_1 = getRunnable(lock2, "lock 2", lock1, "lock 1"); 
    new Thread(try1_2).start(); 
    new Thread(try2_1).start(); 
} 

private static Runnable getRunnable(final ReentrantLock lock1, final String lock1Name, final ReentrantLock lock2, final String lock2Name) { 
    return new Runnable() { 
     @Override 
     public void run() { 
      try { 
       if (lock1.tryLock(1, TimeUnit.SECONDS)) { 
        System.out.println(lock1Name + " acquired in thread " + Thread.currentThread()); 
        if (lock2.tryLock(1, TimeUnit.SECONDS)) { 
         System.out.println(lock2Name + " acquired in thread " + Thread.currentThread()); 
         Thread.sleep(2000); 
        } else { 
         System.out.println("Could not acquire "+lock2Name + " in thread " + Thread.currentThread()); 
         lock1.unlock(); 
         System.out.println(lock1Name + " released in thread " + Thread.currentThread()); 
        } 
       } else { 
        System.out.println("Could not acquire " + lock1Name + " in thread " + Thread.currentThread()); 
       } 
      } catch (InterruptedException e) { 
       //you should not ignore it 
      } finally { 
       if (lock1.isHeldByCurrentThread()) lock1.unlock(); 
       if (lock2.isHeldByCurrentThread()) lock2.unlock(); 
      } 
     } 
    }; 
} 
+1

przykład z Java Współbieżność w praktyce !! ;) –

+1

@assylias Podczas wywoływania zsynchronizowanej metody obiektu wątek automatycznie próbuje uzyskać "blokadę tego obiektu". Podczas gdy przy użyciu "java.util.concurrent.locks.Lock" nie będziemy żądać "zablokowania obiektu", którego metody wywołujemy.Uważam więc, że aby poprawnie używać klasy "Zablokuj", NIE powinniśmy oznaczać metody jako zsynchronizowanej. Ale powinniśmy mieć instancję "Lock" przypisaną do tego obiektu. A przed wywołaniem kodu - który wymaga synchronizacji - powinniśmy przejść do tryLock() na powiązanej kłódce. ---- Plz kontynuuje czytanie poniżej komentarza ------ –

+0

@assylias Tak więc nie blokujemy fizycznie obiektu, którego metodę nazywamy, ale logicznie blokujemy. Podobnie jak mamy balckboard dla każdego obiektu i przed wywołaniem metody, po prostu piszemy na blackboardzie, że "Hej, mam zamek !!" . W rzeczywistości nie blokujemy obiektu. Inny wątek sprawdzi tablicę i zobaczy, że ktoś "powiedział", że ma zamek. Więc nie będzie trwał. Mam rację? –

3

Lock in Java

Use tryLock(timeout, timeunits); 

przejmuje blokadę jeśli jest bezpłatny w wyznaczonym czas oczekiwania i bieżący wątek nie została przerwana. Jeśli blokada jest dostępna, ta metoda zwraca natychmiast z wartością true.

Jeśli blokada nie jest dostępne wówczas bieżący wątek staje niepełnosprawnych na gwint celów planowania i drzemie aż jedna z trzech rzeczy dzieje:

Blokada jest nabyte przez obecnego wątku;

lub inny wątek przerwania obecny gwintu i przerwy nabycia zamka jest obsługiwane;

lub Podany czas oczekiwania upłynie

3

To może pomóc,

Lock lock = null; 
lock=....; 
if (lock.tryLock(15L, TimeUnit.SECONDS)) { 
    try { 
     ........ 
    } finally { 
     lock.unlock(); 
    } 
} else { 
     // do sumthing 
} 
0

W Java 8+ Concurrency API można ustawić wyraźny czas na lock czekać, kiedy to stan jest ustawiony:

private Lock lock = new ReentrantLock(); 
private Condition myCondition = lock.newCondition(); 

try{    
    myCondition.await(1200L, TimeUnit.MILLISECONDS); 
} catch (InterruptedException e) { 
    System.out.println((e); 
} finally{ 
    lock.unlock(); 
} 

Blokada będzie czekać, dopóki nie otrzyma signal() lub signalAll() z innego wątku lub do momentu upłynie czas 1,2 sekundy.