Java Wątki synchornizacja

0

Hej,
Mam problem natury wątków w Java. Staram się ogarnąć ten temat i mam zagwostkę. W programie mam dwa wątki do których przekazuje w konstruktorze ten sam obiekt. I w ramach każdego wątku w metodzie run wywołuje tę samą metodę należacą do tego samego obiektu. W jednym wątku jako argument metody podaje jakąś liczbę a w drugim inną liczbę. Metoda ta ma dopisane synchronized.

I tu moje pytanie , jeżeli mam dwa wątki to wszystko gra , występuje synchronizacja tej metody w sensie , najpierw wykonają się instrukcjie metody w ramach jednego wątku , a potem drugiego. Natomiast gdy zwiększe liczbę wątków do 3 i w górę zaczynają się pojawiać nieporządane efekty typu nie właściwe wartości obliczane w fukcji.

Klasy WatekP3 i WatekP4 wyglądaja analogicznie do tego co posiada WatekP1 z tą różnicą, że dodaje inną liczbę.

Z góry dziękuje za wszelkie odpowiedzi

Podaje kod:

package pl;

public class SzaloneWatki {

public static void main(String[] args) {
	// TODO Auto-generated method stub

	
	Counter Con = new Counter();
	
	WatekP1 w1 = new WatekP1(Con);
	WatekP2 w2 = new WatekP2(Con);
	WatekP3 w3 = new WatekP3(Con);
	WatekP4 w4 = new WatekP4(Con);
	
	w1.start();
	w2.start();
	w3.start();
	w4.start();
	
	
}

}

package pl;

public class WatekP1 extends Thread{

//private int liczbaWatka;

Counter c;

public WatekP1(Counter g) {
	
	this.c=g;
	
	// TODO Auto-generated constructor stub
}


@Override
public void run() {
	// TODO Auto-generated method stub
	
	c.add(4);
	
	
}

}

package pl;

public class WatekP2 extends Thread{

Counter c;

public WatekP2(Counter g) {

	this.c=g;
	
	// TODO Auto-generated constructor stub
}


@Override
public void run() {
	// TODO Auto-generated method stub
	c.add(8);
}

}

package pl;

public class Counter {

int count = 0;

synchronized public void add(int value){

		this.count = this.count + value;
		disp();

}


public void disp()
{
	System.out.println("Count wynosi: "+count);
}

   

}

0

Sformatuj kod.
Jak Ci się objawia błąd? bo w podanym kodzie nie widać, żeby coś się miało źle liczyć.
Bład jest w kawałku kodu, którego nie podałeś.

(No może poza tym, że metoda disp w Counter nie powinna być publiczna).

0

package pl;

public class WatekP3 extends Thread{

Counter c;

public WatekP3(Counter g) {

	this.c=g;
	
	// TODO Auto-generated constructor stub
}


@Override
public void run() {
	// TODO Auto-generated method stub
	c.add(5);
}

}

package pl;

public class WatekP4 extends Thread{

Counter c;

public WatekP4(Counter g) {

	this.c=g;
	
	// TODO Auto-generated constructor stub
}


@Override
public void run() {
	// TODO Auto-generated method stub
	c.add(7);
}

}

A oto efekt działania jak mam w programie głównym tylko dwa pierwsze wątki :

Count wynosi: 4
Count wynosi: 12

Natomiast jak mam sytuację jaką przedstawiłem w kodzie z 4 wątkami

Count wynosi: 4
Count wynosi: 12
Count wynosi: 19
Count wynosi: 24

0

No bo tak to rozumiem:
Count wynosi: 4
Count wynosi: 12
Count wynosi: 17 a w programie wyszło 19
Count wynosi: 24

Chyba że źle coś rozumiem ?

0

No ale przecież wszystko się zgadza, o co chodzi?:D W trzecim princie masz 19 bo pierwsze się dodało 7, potem 5, ty chyba z jakiegoś powodu zakładasz, że to źle.

0

Prawdopodobnie masz problem z wyświetlaniem. Spróbuj zmodyfikować wyświetlanie...

synchronized(System.out) {
  System.out.println("Count wynosi: "+count);
}

--edited: I tak jak napisał @Shadov kolejność wykonania wątków może być różna. To nie jest tak, że synchronized sprawi, że operacje wykonają Ci się w kolejności uruchamiania wątków.

0

Świetnie dzięki wielkie :) Tak przy okazji zapytam się Ciebie o jedną rzecz, bo uruchomiłem ten program teraz kilkukrotnie i na początku było ok, a potem otrzymywałem inne liczby . Z czego to może wynikać ?

0

Rozumiem dzięki wielkie za pomoc :) Trzymajcie się

0

Możliwe, że program zakończył działanie zanim wątki dokończyły swoją pracę. Po uruchomieniu wątków dodaj jakiegoś prostego sleepa np. na 5 sekund i powtórz obserwacje.

0

Już działa jak należy wystarczyło dopisać sleepa i teraz już działa jak należy :) Dzięki wielkie

0

To jeszcze mała uwaga, żebyś się nie nauczył, że sleep pozwoli Ci "synchronizować wątki". W tym konkretnym przypadku sleep daje trochę czasu, przez który mamy nadzieję, że wątki zakończą przetwarzanie (logika, którą wykonują jest bardzo prosta, więc powinny się szybko kończyć i 5 sekund sleepa wyraża tę nadzieję aż nadto). W ogólnym przypadku (wiele wątków coś przetwarza i trzeba poczekać na efekt ich pracy), należy zbudować jakiś mechanizm synchronizacji/czekania na wynik. Zwykły sleep nie jest poprawnym rozwiązaniem.

0

To rozumiem , zdaje sobie sprawę, ale dzięki za wyjaśnienie. W przypadku tego mojego problemu bardziej się zastanawiałem, dlaczego mimo dodania synchronized w odpowiednim miejscu miałem takie efekty. Być możę mechanizm informujący że jeden wątek zakończył działanie i może zostać uruchomiony kolejny. Ale w tym moim przypadku rozumiem to tak, że te wątki działają równolegle. A synchronized pozwala nam zablokować możliwość wykonywania jednocześnie jednej instrukcji kodu przez wiele wątków. Gdyż w moim przypadku ta funkcja :

synchronized public void add(int value){

    this.count = this.count + value;
    disp();

}

Składa się z dwóch instrukcji, a w rzeczywistości dla Maszyny Virtualnej to jest więcej instrukcji m.in odczyt z pamięci wartosci count, dodanie value ..... i tak dalej. I bez synchronized w każdej chwili może nastąpić wstrzymanie wykonywania kodu na rzecz innego wątku, który zacznie wykonywać te same instrukcje.

0

Sorry napisałem ,,możę" :D

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