2015-09-22 23 views
5

Mam metodę o nazwie processOutbox. Chcę, żeby był bezpieczny dla wątków. Nie chcę, aby inny wątek wywoływał tę metodę, gdy jest jeden wątek. Zaimplementowałem to w następujący sposób. Czy zrobiłem to poprawnie? Czy są jakieś luki w mojej implementacji? Jeśli są jakieś, to proszę o poradę, jak mogę to rozwiązać.Jak mogę zapewnić bezpieczeństwo wątków w następującym kontekście?

this.start(); 
    outboxLock.lock(); 
    timer = new Timer(); 
    try{ 
    timer.scheduleAtFixedRate(new TimerTask() { 
      public void run() { 
       processOutbox(); 
      } 
     }, 0, period); 
    } finally{ 
     outboxLock.unlock(); 
    } 
+4

Zamknąłeś tylko planowanie. Wykonanie nadal nie jest bezpieczne dla wątków. – Fildor

+0

Jak mam to zrobić? Proszę o poradę. – mayooran

+0

Proponuję zsynchronizować go na zmiennej statycznej na poziomie klasy. –

Odpowiedz

5

Jeśli chcesz, aby metoda swoją processOutbox, należy użyć słowa kluczowego synchronized:

public class YourClass{ 
    public synchronized void processOutbox(){ 
     //do all you want 
    } 
} 

Więcej informacji na: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Jeśli w kodzie masz instancją YourClass nazywa na przykład myInstance, wszystkie połączenia z processOutbox() będą bezpieczne dla wątków, ponieważ będą zablokowane na poziomie instancji.

Na przykład:

YourClass myInstance = new YourClass(); 
Thread thread1 = new Thread(){ 
    public void run(){ 
     myInstance.processOutbox(); 
    } 
    } 
Thread thread2 = new Thread(){ 
    public void run(){ 
     myInstance.processOutbox(); 
    } 
    } 
thread1.start(); 
thread2.start(); 

Tutaj thead2 będzie czekał aż thread1 kończy wezwanie do "processOutbox"

Ale na przykład:

YourClass myInstance = new YourClass(); 
YourClass myInstance2= new YourClass(); 
Thread thread1 = new Thread(){ 
    @Override 
    public void run(){ 
     myInstance.processOutbox(); 
    } 
}; 
Thread thread2 = new Thread(){ 
    @Override 
    public void run(){ 
     myInstance2.processOutbox(); 
    } 
} 
thread1.start(); 
thread2.start(); 

thead2 będzie NIE czekać ponieważ oni wywołują metodę w różnych instancjach.

Ktoś specjalnie zapytał o używanie ReentrantLock - więc dodam tę odpowiedź do tego, ponieważ ta jest prawidłowa.

public class YourClass { 
    private Lock outboxLock = new ReentrantLock(); 
    public void processOutbox() { 
     outboxLock.lock() 
     try { 
      // do stuff 
     } finally { 
      outboxLock.unlock() 
     } 
    } 
} 

Wspominam o tym specjalnie, ponieważ można też robić rzeczy, gdzie trzymasz innych wątków z zamka bez powodowania je zablokować za pomocą tryLock zamiast.

public class YourClass { 
    private Lock outboxLock = new ReentrantLock(); 
    public void processOutbox() { 
     if(outboxLock.tryLock()) { 
      try { 
       // do stuff 
      } finally { 
       outboxLock.unlock() 
      } 
     } 
    } 
} 
+0

** Nie chcę, aby inny wątek wywoływał tę metodę, gdy jest jeden wątek. ** –

+0

Java API: "Gdy jeden wątek wykonuje zsynchronizowaną metodę dla obiektu, wszystkie inne wątki, które wywołują zsynchronizowane metody dla tego samego obiektu blok obiektu (zawieszenie wykonania), dopóki pierwszy wątek nie zostanie wykonany z obiektem. " –

+0

W jaki sposób mogę osiągnąć to samo za pomocą reentrantlock? proszę o poradę goku :) – mayooran

Powiązane problemy