Wątki - wait(), notify(), notifyAll();

0

To mój pierwszy post na tym forum więc się przywitam :)))
WITAM ;)))
Post ten zamieścilem już na dwóch forach, ale zero odzewu było więc spróbuje tutaj.... :))
Mam problem, otóż dostałem zadanie do zrobienia z wątków.
Chodzi o program, który ma 3 wątki. Mają one po kolei wypisywać na ekranie 1 , 2 , 3.. Wątek jeden wypusuje 1, drugi 2 itd...
To co się dzieje w metodzie run() ma być w bloku synchronized (nic nowego chyba ;P) ogólnie program ma wyglądać tak jak napisałem...chyba...
Problem tkwi w tym, że to co ja napisałem wykonuje się tylko raz, a nie kilka...
Bardzo bym prosił o wyjaśnienie co mam źle w tym kodzie :)))

oto kod:

class Licznik 
{
    public int n = 1;

}

class T1 extends Thread
{
    Licznik t;
    T1(Licznik z)
    {
        t = z;
    }

    public void run()
    {

    synchronized (this)
    {
        while(true)
        {
            while(t.n!=1)
            {
                try {wait();
                } catch(InterruptedException exc) {}
            } 

        System.out.println("1 ");
        t.n=2;
        this.notify();
        }
    }
    }   
}

class T2 extends Thread
{
    Licznik t;
    T2(Licznik z)
    {
        t = z;
    }
    public void run()
    {
    synchronized (this)
    {
    while(true)
    {       
        while(t.n!=2)
        {
            try {wait();} catch(InterruptedException exc) {}
        }
        System.out.println("2 ");
        t.n=3;
        this.notify();

    }
    }

}}
class T3 extends Thread
{
    Licznik t;
    T3(Licznik z)
    {
        t = z;
    }
    public void run()
    {
    synchronized(this)
    {
    while(true)
    {
        while(t.n!=3)
        {
            try {wait();} catch(InterruptedException exc) {}
        }

        System.out.println("3 ");
        t.n=1;
        this.notifyAll();

}}
    }
}

public class Zadanie
{
    public static void main (String [] args)
    {
        Licznik licznik = new Licznik();
        T3 t3 = new T3(licznik);
        T1 t1 = new T1(licznik);
        T2 t2 = new T2(licznik);

        t1.start();
        t2.start();
        t3.start();

    }
}

Czekam na cenne uwagi :)

0

Proste.
Jeżeli synchronizujesz coś takiego:

synchronized(this){
    while(true){
      //...
   }
}

To popatrz co się stanie. Odpalasz pierwszy wątek i w tym momencie zostaje rozpoczęta synchronizacja. Oznacza to, że do momentu aż nie zostanie zakończona operacja przeprowadzana przez ten wątek inne wątki nie będa uruchamiane. Problem polega na tym, że synchronizowaną operacją jest nieskończona pętla! Zatem operacja synchronizowana nigdy się nie zakończy i tym smaym inne wątki nigdy nie zostaną uruchomione.

0

Ten program po skompilowaniu wyświetla 1 , 2 , 3 więc nie są blokowane...
Chodzi o to, ze wyswietla tylko raz, oczywiscie mogę dać tam petle for(int i=0; i<3;i++) ale będzie to samo bo sprawdzałem....
Wydaje mi się, ze to jest kwestia złego rozmieszczenia wait() i notify() (ale moge się mylić...)
Poaztym jeżeli nie dam tego w pętli, to sie nie będzie powtarzało wypisywanie, bo jak sie skończy metoda run() to wtedy wątek kończy swój żywot....

Właśnie spróbowałem dac bloki synchronized() niżej, czyli zaraz po "while(true) {" i taki sam efekt....

0

oj koziolek koziolek
od kiedy to synchronizacja uniemozliwia ruszenie innych watkow?
tutaj problemem jest ze wolana jest metoda wait(), blokujaca watek, a pozniej dalej wolana jest notify() -problem w tym ze do tego wywolania zaden watek nie dojdzie - pamietaj ze zaden watek po wywolaniu wait() sam na sobie nie wywola notify() - to musi zrobic inny watek, a jako ze nie masz nigdy pewnosci ktory z watkow czekajacych na jakis warunek (wait()) zostanie zawiadomiony, bezpieczniej jest wywolac notifyAll()
ty natomiast nie masz na czyms wywolac tego notify(), poniewaz w run() synchronizujesz na this, a zaden inny watek nie ma referencji do pozostalych 2 watkow
dzialanie - wszystkie watki startuja, synchronizuja sie na sobie, i czekaja az ktos wywola na nich notify(), ale NIKT tego nie moze zrobic

polecam koledze zapoznac sie dokladniej z watkami i waitami notifajami itp (koziolkowi rowniez :>)
pozdrawiam

PS rogaty nie obrazaj sie, wiem ze kkazdy moze sie pomylic, tak tylko sobie zartuje ;-) peace

0

Nigdy nie byłem mocny z współbieżności. Sensownie wygląda to co mówisz. Ja bym dodał jeszcze, że wypadało by przerobić te trzy klasy w jedną, która będzie bardziej ogólna. I kodu mniej i jakoś łatwiej zrozumieć jak wszytko w jednym miejscu. Funkcjonalność związaną z numerowaniem można zastąpić warunkiem z resztą z dzielenia.


ide se poczytać.

1

Dzięki wielkie "oj koziołku" :))
Na dwóch forach dałem i nikt nie odpisał :))
Zrobiłem, śmiga, w sumie nie pomyślałem ze tym "this" tak było w przykładach, a wiadomo ze trzeba podać obiekt do którego w danym czasie ma dostęp tylko jeden wątek :))
tutaj zamieszczam poprawiony kod :))) zmienilem while(true) na "for", żeby sie nie wykonywąło w nieskończoność :))

class  Licznik 
{
     public int n = 1;

}

class T1 extends Thread
{
    Licznik t;
    T1(Licznik z)
    {
        t = z;
    }

    public void run()
    {

for (int i=0;i<3; i++) {    
    synchronized (t)
    {
            while(t.n!=1)
            {
                try {t.wait();
                } catch(InterruptedException exc) {}
            } 

        System.out.print("1, ");
        t.n=2;
        t.notify();
        }
    }
    }   
}

class T2 extends Thread
{
    Licznik t;
    T2(Licznik z)
    {
        t = z;
    }
    public void run()
    {
for (int i=0;i<3; i++) {

    synchronized (t)
    {
        while(t.n!=2)
        {
            try {t.wait();} catch(InterruptedException exc) {}
        }
        System.out.print("2, ");
        t.n=3;
        t.notify();

    }
    }

}}
class T3 extends Thread
{
    Licznik t;
    T3(Licznik z)
    {
        t = z;
    }
    public void run()
    {
    for (int i=0;i<3; i++){

            synchronized(t)
    {
        while(t.n!=3)
        {
            try {t.wait();} catch(InterruptedException exc) {}  
        }

        System.out.println("3 ");
        t.n=1;
        t.notifyAll();
}
}   }
}

public class Zadanie
{
    public static void main (String [] args)
    {
        Licznik licznik = new Licznik();
        T3 t3 = new T3(licznik);
        T1 t1 = new T1(licznik);
        T2 t2 = new T2(licznik);

        t1.start();
        t2.start();
        t3.start();

    }
}

JESZCZE RAZ WIELKIE DZIĘKI :))))

Jeżeli chodzi o zebranie w jedną klasę, to zadanie wlaśnie miało posiadać trzy klasy z wątkami, wiec już nie bede kombinował :))
Jeżeli chodzi o zastosowanie reszty z dzielenia to wydaje mi sie, że warunek z dodawaniem jest mniej czasochłonny niż operacja dzielenia....
Pozdrawiam

0

zeby sobie pocwiczyc napisalem takie cos, zawierajac wskazowki koziolka:

class Licznik {
public int n = 1;

public Licznik() {
    reset();
}

public int getValue() {
    return n;
}

/*synchronized*/ public void increment() {
    // wydaje sie ze metoda powinna byc synchronizowana
    // poniewaz 3 watki beda sie do niej dobierac
    // ale to tylko w teorii - poniewaz tak mamy napisany program ze wiemy
    // ze na raz tylko jeden watek moze ja wywolac bo reszta czeka na
    // notify() wiec mozna synchronized wywalic
    // gdybysmy takiej wiedzy nie mieli to bysmy musieli to zostawic
    ++n;
    if (n == 4) {
        // jesli 4, to przekrecamy licznik
        n = 1;
    }
}

public void reset() {
    n = 1;
}

}

class MyThread extends Thread {

private Licznik t;

private int output;

public MyThread(Licznik z, int output) {
    t = z;
    this.output = output;
}

public void run() {
    while (true) {
        synchronized (t) {
            while (t.getValue() != output) {
                // jesli nie moja kolej wypisac to czekam
                // robimy to w petli ze wzgledu na to ze moze to i tak nie nasza kolej
                // tylko tego drugiego ;-)
                try {
                    t.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }
            // doszlismy tutaj wiec pora wypisac
            // jesli to 3, to dajemy nowa linie, ladniej widac wszystko
            System.out.print(output + (output == 3 ? "\n" : " "));
            // zwiekszyc licznik
            t.increment();
            // oraz zawiadomic pozostale 2 watki ze ktorys z nich moze
            // wykonac swoj kod
            t.notifyAll();
        }
    }
}

}

public class Test {

public static void main(String[] args) {
    Licznik licznik = new Licznik();
    MyThread t1 = new MyThread(licznik, 1);
    MyThread t2 = new MyThread(licznik, 2);
    MyThread t3 = new MyThread(licznik, 3);

    t1.start();
    t2.start();
    t3.start();
}

}

0

Jeżeli chcesz nauczyć się wielowątkowość w javie, to zapoznaj się z pakietem java.util.concurrent(od javy 5)
Są tam, np. java.util.concurrent.atomic.AtomicInteger, czyli integer na którym pewne operacje są atomowe, czy java.util.concurrent.ArrayBlockingQueue dzięki której można w banalny sposób wykonać schemat producenci-konsumenci.

Jeżeli do synchronizacji używa się tylko synchronized() i notify(), to po pewnym czasie coraz trudniej przewidzieć wszystkie przebiegi wątków.


 /*synchronized*/ public void increment() 

Masz rację, w tym szczególnym przypadku synchronized nie jest konieczne.

0

__krzysiek85, dzięki za radę :))
Moim zadaniem było właśnie wykorzystać wait(), notify() i notifyAll()...
Jeżeli będe chcial bardziej zgłębić współbieżność wtedy sięgnę po tę klasę :)))
Pozdro

Temat uważam za zamknięty :))

0

Mimo że temat zamknięty, to coś napiszę. U mnie twój kod nie działa. Zadziałał jak zmieniłem notify() na notifyAll().
pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0