Wywołanie Thread.join w wątku mającym Lock

0

Witam

Staram się ogarnąć coś ze współbieżności javy i tworzę różne mało użyteczne przykłady w celach dydaktycznych. Mam takie pytanie do przykładu który zamieściłem poniżej: Dlaczego Thread viewer nie wywołuje się w wątku t4 który ma założony lock? Wcześniej na wszelki wypadek zdejmuje ten lock ale i tak nie pomaga.Komunikaty na konsoli nie wskazują aby inny wątek niż viewer przejmował wtedy blokadę. W programie jeden wątek inkrementuje zmienną a drugi ją dekrementuje.

`
public class WspoldzielenieZasobow {

static volatile int d = 0;
static volatile boolean flag = false;

public static void main(String[] args) {
    
  

     final Lock lock = new ReentrantLock();
     
     
      Thread viewer = new Thread() {
            @Override public void run() {
                while(true) {
                System.out.println(d);
                try {
                Thread.sleep(1000);
                }
                catch(InterruptedException e) {
                    System.out.println(e);
                }
                }
            }
        };
     
     
     Thread t3 = new Thread() {
        @Override public void run() {
            boolean isLock = false;
            while(true) {
            if( !flag && (isLock = lock.tryLock())) {
                try {
                    System.out.println("Wywolanie t3");
                    d++;
                    flag = true;
                }
                finally {
                    if(isLock) 
                        lock.unlock();
                    Thread.yield();
                }
            }
            }
        }
     };
     
     
        Thread t4 = new Thread() {
        @Override public void run() {
            boolean isLock = false;
            while(true) {
            if( flag && (isLock = lock.tryLock())) {
                try {
                    System.out.println("Dekrementacja t4: " + (--d));
                    flag = false;
                try {
                System.out.println("Proboa wywolania viewer.join()");
                lock.unlock();
                viewer.join();
                lock.lock();
                    
                Thread.sleep(1000);
                }
                catch(InterruptedException e) {
                    System.out.println(e);
                }
                }
                finally {
                    if(isLock) 
                        lock.unlock();
                    Thread.yield();
                }
            }
            }
        }
     };
        
    
        t3.start();
        t4.start();

}
}
`

0

Thread.join() nie wywołuje innych wątków. Czeka aż wątek będzie martwy.

0

Czyli powinienem najpierw wywołać viewer.start() a poźniej viewer.join()? Tylko że to nadal nie chce działać :(

0

Wątek wywołujący viewer.join() czeka do śmierci wątku viewer.

0

W "Thinking in Java" czytam: "Wątek może wywołać metodę join() innego wątku, co sprawi, że realizacja wątku wywołującego zostanie wznowiona dopiero po zakończeniu wątku, którego metoda join() została wywołana. Jeśli jeden wątek wywoła metodę t.join() innego wątku t, to realizacja wątku wywołującego zostanie wstrzymana aż do czasu zakończenia wątku t."

W z tego co zrozumiałem to wątkiem wywołującym w moim programie jest t4 i wywołuje on metodę join() wątku viewer. Tym samym wątek t4 powinien zostać zawieszony i poczekać na realizację wątku viewer.

0

I dokładnie tak robi.

i poczekać na realizację wątku viewer.

Czyli poczekać na zakończenie wątku viewer.

0

No tak, ale wątek viewer nie realizuje swojego zadania ponieważ ma wyświetlić zmienną d a tego nie robi :( Przepraszam za upierdliwość ale zależy mi by to zrozumieć.

1

Jak uruchomisz wątek viewer (viewer.start()) to wątek będzie realizował swoje zadanie (wypisywał coś na ekran).
Zakończy się gdy dojdzie do końca metody viewer.run() (przy while(true) ciężko o to).
viewer.join() czeka na koniec, a nie realizację wątku.

0
Delor napisał(a):

Jak uruchomisz wątek viewer (viewer.start()) to wątek będzie realizował swoje zadanie (wypisywał coś na ekran).
Zakończy się gdy dojdzie do końca metody viewer.run() (przy while(true) ciężko o to).
viewer.join() czeka na koniec, a nie realizację wątku.

Z tego co mówisz wynika że program nie może się nigdy skończyć, no bo w viewer jest while(true) a t4 czeka na jego zakończenie, tak?

0
Kuben napisał(a):
Delor napisał(a):

Jak uruchomisz wątek viewer (viewer.start()) to wątek będzie realizował swoje zadanie (wypisywał coś na ekran).
Zakończy się gdy dojdzie do końca metody viewer.run() (przy while(true) ciężko o to).
viewer.join() czeka na koniec, a nie realizację wątku.

Z tego co mówisz wynika że program nie może się nigdy skończyć, no bo w viewer jest while(true) a t4 czeka na jego zakończenie, tak?

:Okej teraz zadziałało, przyczyną całego niedziałania programu był brak viewer.start(). Myślałem że join spowoduje wywołanie wątku. Dzięki za pomoc :)

0

A jeszcze mam pytanie z innej beczki: Dlaczego nie trzeba zdejmować blokady Lock przy wywołaniu viewer.join()? Spróbowałem bez unlocka i też działa. W końcu wywołanie viewer przerywa prace t4... Czym jest de facto blokada tutaj? Czy w tym kontekście jest to działania na zasadzie Thread.sleep, czyli udostępnienie z całego czasu przydzielonego na wykonanie zadania t4.run fragmentu czasu na wywołanie viewer?

0

W viewer nie sprawdzasz blokady.

0
Delor napisał(a):

W viewer nie sprawdzasz blokady.

Aha czyli gdybym dodał tam sekcje if( lock.tryLock()) to wtedy viewer mógłby nie zrealizować zadania? A w przeciwnym razie blokada go nie obowiązuje, więc może działać kiedy chce?

0

Dokładnie.

0

Ok a załóżmy że zamiast jawnej blokady byłby tam blok synchronized. Rozumiem to tak, że wtedy wywołanie viewer.join nie powoduje zdjecia blokady t4, jedynie wywołujący wątek, który posiada aktualnie blokadę (tutaj t4) użycza czasu procesora dla wywołania zewnętrznego wątku i wznowi działanie gdy ten wątek sie zakończy. Blokada zostanie zdjęta dopiero po całkowitym zakończeniu t4. Do tego czasu nie może działać żaden wątek poza tymi, które zostały wywołane przez t4. Dobrze to sobie tłumacze?

0

Zależy na czym będziesz miał ten blok synchronized. Blokada będzie zdjęta po wyjściu z bloku.

0

Zależy na czym? No np. tak jak w zamieszczonym przeze mnie przykładzie, tylko zamiast Lock. Są jakieś szczególne przypadki pozbawienia wątku blokady przed wyjściem z synchronized?

0

Synchronized robisz na obiekcie. Na czym będzie w Twoim przykładzie? Na obiekcie lock? To będzie działać identycznie.
Z tym że z wątek z blokadą na Lock możesz przerwać (interupt()) a z blokadą synchronized nie możesz.

0
Delor napisał(a):

Synchronized robisz na obiekcie. Na czym będzie w Twoim przykładzie? Na obiekcie lock? To będzie działać identycznie.
Z tym że z wątek z blokadą na Lock możesz przerwać (interupt()) a z blokadą synchronized nie możesz.

Miałem na myśli blokadę na this po prostu. Nie rozumiem po co robić blokadę na obiekcie lock... Blokadę robi się na obiekcie którego metody będzie się wywoływać, zgadza się? Lock de facto do niczego już nie jest potrzebny jeśli używamy bloku synchronized.

0

Dla każdego run() this jest innym obiektem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.