Błąd podczas wywołania metody zatrzymującej pulę wątków

0

Mam taki problem, że jak wywołuje metodę, która ma zatrzymać wątki to zwraca mi błąd :

java.lang.IllegalMonitorStateException

w tej metodzie mam taki kod:

//wcześniej w kodzie:
	service = Executors.newFixedThreadPool(threads);
///metoda

try {
			service.wait();
			stop = true;
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

będę wdzięczny za pomoc, bo jestem strasznie zielony jeśli chodzi o programowanie współbieżne

1

Po pierwsze metodą wait() nie zatrzymujesz, ale zawieszasz, wstrzymujesz wątek.

Po drugie zawiesiłeś wykonywanie wątku, w którym wykonywana jest metoda, która miała zatrzymywać wątki.

Po trzecie wątek próbujesz wstrzymać na monitorze, do którego nie masz prawa i stąd ten wyjątek.

Po czwarte, żeby mieć prawo do monitora, wywołanie wait() musi być w bloku synchronizowanym właśnie na na tym monitorze, u Ciebie obiekcie service.

Po piąte dlaczego monitorem jest u Ciebie obiekt puli wątków service?

Po szóste, jeśli chodzi Ci o zatrzymywanie w sensie zakończenia wątku, to jedynym rozsądnym rozwiązaniem jest rutynowe kończenie wątku, czyli np. w wątku, który wykonuje swój kod w pętli trzeba zmienić jej warunek, aby zakończyć iteracje. Do tego służy metoda interrupt klasy Thread, ale wątek musi być przygotowany na ten sygnał testując go co jakiś czas metodą isInterrupted().

1

Nie musisz iterować po wątkach. Jeśli wątki testują isInterrupted() to masz do wyboru metodę shutdownNow() z serwisu, która zwróci listę wątków, których nie udało się zatrzymać i awaitTermination(timeout, unit, ), która będzie czekać podany czas, aż zakończą się wszystkie taski i zwróci true jeśli się udało. Oracle zaleca połączyć obie:

service.shutdown();
try {
    if (!service.awaitTermination(800, TimeUnit.MILLISECONDS)) {
        service.shutdownNow();
    } 
} catch (InterruptedException e) {
    service.shutdownNow();
}
0

Dobra a mam jeszcze pytanie. Czy pętla po ilości wątków:

for (i = 0; i < this.numberOfThreads; i++) {
			service.submit(task);
			service.submit(task1);
			service.submit(task2);
		}

przydziela każdemu zadaniu tylko 1 wątek? A jeśli tak, to w jaki sposób przydzielać zadaniu max ilość dostępnych wątków?

0

Hmm, submit to jedynie zatwierdzenie wątku do wykonania. W tym przypadku task i wątek to to samo. Osobiście jeszcze nie słyszałem o takiej magii, żeby jakieś zadanie, w sensie napisana metoda, została automatycznie podzielona na więcej wątków. Niestety trzeba samodzielnie zadanie zaprogramować na wątki zapewniając koordynację.

0

Czyli konkretniej jak to zrobić, bo im bardziej zagłębiam się w tą tematykę tym mniej czaję. Czy jeśli w jakimś task nie mam bloku synchronized lub lock to wszystkie wątki maja tam dostęp a jeśli jest to tylko ten który był 1 i podniósł semafor?

0

Może zacznij od tego co mają robić te wątki, bo jest dużo możliwych rozwiązań.

0
// jakaśn pętla
    punkt = generator.getPoint()
    liczbaPunktów++
licz wektory 
licz histogram

Mam coś takiego (pseudokod) i mam to rozbić na wątki.Podzieliłem to na 3 task ale to chyba nie działa, więc chciałbym żeby z dostępnej puli wątków część robiła: punkt = generator.getPoint() jak będę wiedział jak to ogarnąć to z resztą sobie poradzę. W skrócie chodzi o równoległe prowadzenie obliczeń ale jakoś nigdzie w google takiego przykładu znaleźć nie mogę

1

Możesz wykorzystać jakieś gotowe rozwiązanie problemu, np. producentów i konsumentów, wtedy n-wątków generuje punkty, które są wstawiane do wspólnego bufora punktów, kolejne m-wątków pobiera z tego bufora punkty i liczy wektory, które wstawiasz do bufora wektorów i na końcu wątek odpowiedzialny za liczenie histogramu pobiera je z tego bufora. Wtedy wątki producentów i konsumentów są banalne np. dla producenta to obliczenie wartości i wstawienie do bufora.
Możesz też odpalać wątki klasy Callable dla każdego generowanego punktu, wynik otrzymywać jako Future, i potem to samo dla licz punkty i licz histogram.
Przykład monitora
Przykład ServiceExecutor

0

Ok super. Zobaczę jak to zaimplementuje u siebie i w razie co będę pytał :)

0

Pytanie jak wiele wątków ma pobierać dane z generator.getPoint(), czy dla każdego wątku mam robić metodę run czy jest inny sposób?

0

Z przykładu:

class PointGenerator implements Callable<Double>{
    private double pointData;
    
    public PointGenerator(double pointData){
        this.pointData = point;
    }
    
    public Double call() throws Exception {
        //oblicz i zwróć point na podstawie pointData
    }
}

potem tylko tworzysz kolejne obiekty tej klasy z kolejnymi pointData i uruchamiasz wątki.
Jeśli liczenie tych punktów nie jest zbyt pracochłonne, to możesz generować ciąg punktów w jednym wątku i wtedy pointData to może być zakres, a wartością zwracaną tablica punktów. To już zależy jak dużo dzieje się w trakcie obliczania tego punktu. Jeśli to jest proste wyrażenie to nie opłaca się odpalać jednego wątku na punkt.

0

Czy ta linijka z twojego przykładu wyniki=(ArrayList<Future<Double>>) exec.invokeAll(zadania); uruchamia wszystkie dostępne wątki z puli?

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