Współbieżność - synchronizowany stos

0

Witam, potrzebuje pilnej pomocy, temat: problem producentów i konsumentów z wykorzystaniem stosu.
Coś tam sklepałem, ale nie działa tak jak powinno i proszę Was o pomoc, błędy pewnie trywialne, ale cóż.. uczę się :)

public class Stack {
	private int [] tab;
	private int wierzch = 0;
		
	
	
		/***************** Konstruktor (rozmiarStosu) ****************/
	
	public Stack(int rozmiar) {
		tab = new int[rozmiar];
        wierzch = 0;
	}
	
	/********************* Produkcja ************/
	
	 public synchronized void push(int E)  {
        if (wierzch < tab.length) {
            tab[wierzch] = E;
            wierzch++;
            System.out.println("\nWyprodukowano element: " +tab[wierzch]);
            notifyAll();
        } else {
        	try {
				System.out.println("\nMagazyn pełny, producnet czeka...\n");
        		Thread.currentThread().wait();
				
			} catch (InterruptedException e) {
			}
        }
	}
	
	/******************** Konsumpcja **************/
	 
	public synchronized int pop() {
        if (wierzch <= 0) {
            try {
            	System.out.println("\nMagazyn pusty, konsument czeka...\n");
				Thread.currentThread().wait();
			} catch (InterruptedException e) {
			}
        }
        int temp = tab[wierzch - 1];
        wierzch--;
        System.out.println("Skonsumowano element: " +tab[wierzch]);
        return temp;
    }
 
	
	/******************** MAIN **********************/
	public static void main(String [] args) {
		Stack stos = new Stack(100);
		for(int i = 0; i<20;i++) {
			new Producent(stos).start();
			new Konsument(stos).start();
		}
		
	}



}
	

import java.util.Random;


public class Producent extends Thread {
	Stack stos;
	public Producent(Stack stos) {
		this.stos = stos;
		
		
	}
	@Override
	public void run() {
		Random r = new Random();
		stos.push((r.nextInt())/100000);
		
		
	}
	


}




public class Konsument extends Thread {
	
		Stack stos;
		public Konsument(Stack stos) {
			this.stos = stos;
			
			
		}
		@Override
		public void run() {
			stos.pop();
			

		}
}

Pozdrawiam i proszę o wyrozumiałość.

0

Na moje oko problem jest gdy stos jest pełny. W taki przypadku usypiasz wątek, który dalej używa synchronizowanej metody i blokuje stos.

Spróbuj zrobić tak:
Synchronizujesz metody pop i push, ale w przypadku gdy stos jest jest pełny rzucasz wyjątek że tak jest lub metoda push jest typu boolean zwracająca informację czy udało się dodać coś do stosu czy nie.
W obu rozwiązaniach producent dostaje informację czy operacja się powiodła czy nie, ale w przypadku błędu nie blokuje stosu. Wtedy może sam siebie uśpić na jakiś czas i spróbować ponownie gdy miejsce na stosie się zwolni.

0

Wyprodukowano element: -10347
Skonsumowano element: -10347
Exception in thread "Thread-0" Exception in thread "Thread-1"
Wyprodukowano element: 16002Exception in thread "Thread-2"
Skonsumowano element: 16002

Wyprodukowano element: -11559
Exception in thread "Thread-5" Exception in thread "Thread-4" Skonsumowano element: -11559
Exception in thread "Thread-3" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Producent.run(Producent.java:15)
java.lang.IllegalMonitorStateException

Wyprodukowano element: -15324
at java.lang.Object.notifyAll(Native Method)
at Konsument.run(Konsument.java:14)

Wyprodukowano element: -7323
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Konsument.run(Konsument.java:14)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Producent.run(Producent.java:15)
Skonsumowano element: -7323
Exception in thread "Thread-9" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)Skonsumowano element: -15324

at Konsument.run(Konsument.java:14)

java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Producent.run(Producent.java:15)
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Producent.run(Producent.java:15)
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Konsument.run(Konsument.java:14)
Exception in thread "Thread-7" Exception in thread "Thread-6" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Konsument.run(Konsument.java:14)
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Producent.run(Producent.java:15)

Wyprodukowano element: 13628
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at Producent.run(Producent.java:15)
Skonsumowano element: 13628
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException

Wyprodukowano element: 14144
at java.lang.Object.notifyAll(Native Method)
at Konsument.run(Konsument.java:14)
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException
Skonsumowano element: 14144

ITD ITD

0

aby korzystać z metod wait i notify* należy mieć wyłączność na obiekt z którego monitora się używa, co zresztą masz w wyjątkach. Ogólnie, wykonujesz notifyAll na monitorze aktualnego wątku, natomiast sekcję krytyczną masz względem obiektu Twojego stosu.

poprawnie byłoby:

synchronized(obiekt_blokady){
obiekt_blokady.wait()
} 

synchronized(obiekt_blokady){
obiekt_blokady.notifyAll();
}
 

w Twoim przypadku wygodniej byłoby korzystać z obiektów Condition.

0

Bardzo dziekuje za odpowiedź. Jednak mam spory problem ze zrozumieniem tego. Jak to zastosowac konkretnie w moim przykladzie ?

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