[Java] Watki + Swing + problem 5 filozofów

0

może na poczatku dam kod

import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JButton;
import java.awt.Rectangle;
import java.awt.Dimension;

public class MFrame extends JFrame {
	private int wlkRamki = 500;
	private static final long serialVersionUID = 1L;
	private MPanel jContentPane = null;
	private JButton jButtonStart = null;
	private JButton jButtonStop = null;
	

	/**
	 * This method initializes jButtonStart	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJButtonStart() {
		if (jButtonStart == null) {
			jButtonStart = new JButton();
			jButtonStart.setBounds(new Rectangle(450, 20, 50, 50));
			jButtonStart.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
					jContentPane.stol.run();
				}
			});
		}
		return jButtonStart;
	}


	/**
	 * This method initializes jButtonStop	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJButtonStop() {
		if (jButtonStop == null) {
			jButtonStop = new JButton();
			jButtonStop.setBounds(new Rectangle(520, 20, 50, 50));
			jButtonStop.addActionListener(new java.awt.event.ActionListener() {
				public void actionPerformed(java.awt.event.ActionEvent e) {
				}
			});
		}
		return jButtonStop;
	}


	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				MFrame thisClass = new MFrame();
				thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				thisClass.setVisible(true);
			}
		});
	}


	public MFrame() {
		super();
		initialize();
	}

	private void initialize() {
		this.setSize(609, 628);
		this.setContentPane(getJContentPane());
		this.setTitle("JFrame");
		
		
	
	}


	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new MPanel();
			jContentPane.setLayout(null);
			jContentPane.add(getJButtonStart(), null);
			jContentPane.add(getJButtonStop(), null);
			
		}
		return jContentPane;
	}

}  
import java.awt.Graphics;


import javax.swing.JPanel;


public class MPanel extends JPanel{
	Graphics G;
	Stol stol;
	
	public MPanel(){
		stol = new Stol();
		
	
	}
	protected void paintComponent(Graphics g) {
		G = g;
		stol.rozdajWidelce(g);
		System.out.println("widelce rozdane");
	}
	
	

}
import java.awt.Graphics;

import javax.swing.JPanel;


class Stol extends Thread{
	
	final static int X = 300;
	final static int Y = 320;
	Widelec[] widelce;
	Gosc[] goscie;
	Graphics G;
	
	public Stol(){
		widelce = new Widelec[17];
		goscie = new Gosc[9];
		for(int i = 1;i<17;i++){
			widelce[i] = new Widelec();
		}
		for(int i = 1;i<9;i++){
			goscie[i] = new Gosc();
		}


	}
	void rozdajWidelce(Graphics g){
		G = g;
		ulozWidelce(g);
		przydzielWidelce();


	}
	
	private void ulozWidelce(Graphics g){
		widelce[7].setWidelec(g, 300, 50, 550, 483);
		widelce[4].setWidelec(g, 550, 483, 50, 483);
		widelce[1].setWidelec(g, 50, 483, 300, 50);
		
		widelce[12].setWidelec(g, X, Y-50, X+75, Y+80);
		widelce[10].setWidelec(g, X+75, Y+80, X-80, Y+80);
		widelce[11].setWidelec(g, X-80, Y+80, X, Y-50);
		
		widelce[16].setWidelec(g, X, Y-50, X, Y+30);
		widelce[14].setWidelec(g, X, Y+30, X-80, Y+80);
		widelce[15].setWidelec(g, X, Y+30, X+75, Y+80);
		
		widelce[5].setWidelec(g, X, Y-50, 300, 50);
		widelce[9].setWidelec(g, X+75, Y+80, 550, 483);
		widelce[3].setWidelec(g, X-80, Y+80, 50, 483);
		
		widelce[6].setWidelec(g, 340, 200, 300, 50);
		widelce[8].setWidelec(g, 340, 200, 550, 483);
		widelce[2].setWidelec(g, 340, 200, 50, 483);
		widelce[13].setWidelec(g, 340, 200, X, Y+30);
	}
	private void przydzielWidelce(){
		goscie[1].dajWidelce(widelce[1], widelce[2], widelce[3], widelce[4]);
		goscie[2].dajWidelce(widelce[1], widelce[5], widelce[6], widelce[7]);
		goscie[3].dajWidelce(widelce[7], widelce[8], widelce[9], widelce[4]);
		goscie[4].dajWidelce(widelce[3], widelce[11], widelce[14], widelce[10]);
		goscie[5].dajWidelce(widelce[10], widelce[15], widelce[12], widelce[9]);
		goscie[6].dajWidelce(widelce[16], widelce[11], widelce[12], widelce[5]);
		goscie[7].dajWidelce(widelce[13], widelce[14], widelce[15], widelce[16]);
		goscie[8].dajWidelce(widelce[2], widelce[13], widelce[6], widelce[8]);
		
	}
	
	public void run(){
		goscie[1].run();
	}
}
public class Gosc extends Thread{
	
	int nr;
	Widelec w1,w2,w3,w4;
	public void dajWidelce(Widelec w1, Widelec w2, Widelec w3, Widelec w4){
		this.w1 = w1;
		this.w2 = w2;
		this.w3 = w3;
		this.w4 = w4;
	}
	public void run() {

		w1.use();



	}
			

}


import java.awt.Color;
import java.awt.Graphics;

class Widelec {
	int x1,y1,x2,y2;
	Graphics g;
	
	
	public void setWidelec(Graphics g, int x1, int y1, int x2, int y2){
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		this.g = g;
		initialize();
	}
	
	public void initialize(){
		g.drawLine(x1, y1, x2, y2);

	}
	public void use(){
		g.setColor(new Color(255,0,0));
		g.drawLine(x1, y1, x2, y2);
	}
	
	public void putBack(){
		g.setColor(new Color(255,255,255));
		g.drawLine(x1, y1, x2, y2);
	}
}

a moje pytanie jest nastepujace:

Dlaczego podczas wcisniecia jButtonStart w JFrame program wchodzi do funkcji

	public void use(){
		g.setColor(new Color(255,0,0));
		g.drawLine(x1, y1, x2, y2);
	}

ale polecienie g.drawLine(x1, y1, x2, y2); nie rysuje czerwonej linii.

pozdrawiam

0

Pewnie dlatego, że wcześniej nie został wywołany setWidelec().
Obiekt jest tworzony z domyślnymi wartościami x1, y1, x2, y2 równymi zero., a g z null.
De facto więc setWidelec pełni uboczną rolę konstruktora. Tak oczywiście nie powinno być. Konstruktor zwykle coś robi, a prawidłowa inicjacja pól jest jego pierwszorzędnym zadaniem.
Sytuacje w której należy pozostawić konstruktor domyślny są na tyle rzadkie, że należy zawsze podawać powód takiej decyzji w dokumentacji klasy.
Jeżeli program nie zgłasza wyjątku NullPointerException, to znaczy, że g oraz pozostałe zmienne zostało przypisane poprzednimi wywołaniami. Program więc nie tyle nie tworzy linii, ile wyrysowuje w miejscu już wyrysowanych.

Oczywiście mogą być i inne błędy, ale nie mogę się na tym skupić bardziej tego dnia. :)

0

ja na poczatku mialem konstruktor, ale wtedy mam problem z przekazaniem referencji do g klasie widelec i nie moglem narysować linii.
A tak zauważ jak funkcje Stol:rozdajWidelce(g); Stol:ulozWidelce(g); i Widelec:setWidelec(g, x1, y1, x2, y2); przekazuja z wnetrza funkcji protected void paintComponent(Graphics g) referencje do g.

Nie wiem jak w inny sposob zainicjować referencje do Graphics g.

0

Twój problem z grafiką i urządzeniem do rysowania jest kompletnie wtórny. Jego przyczyną jest błędna koncepcja programu.

Najpierw rzuć okiem na to:
http://www.algorytm.org/index.php?option=com_content&task=view&id=55&Itemid=26

A potem spróbuj przerobić koncepcję swojego programu tak, aby rozwiązać problem bez grafiki. Wizualizacja, to tylko produkt uboczny rozwiązywania problemu i zawsze warto ją wrzucić do osobnego modułu logicznego.
Najlepiej by było gdyby metoda paint() odrysowywała bieżący stan stołu, filozofów i widelców, ale nie brała żadnego udziału w algorytmie przeprowadzającym obliczenia/sterowanie.
Nie warto też tworzyć bytów, które nic nie wnoszą do samego sedna działania programu. Kilka sugestii: Konstruuj stół od razu z położonymi widelcami i nie zajmuj się ich rozkładaniem w samym algorytmie - to zadanie konstruktora; uwzględnij, że jedyną funkcją stołu jest organizacja miejsc dla filozofów i dostęp do widelców; dostęp do widelców (operacje na nich - czyli podniesienie i opuszczenie) musi być synchronizowany tak aby zakleszczenie nie nastąpiło, synchronizuj dostęp tylko do pojedynczych widelców - nie do nich wszystkich na raz. Stół nie powinien być wątkiem, samoistnym wątkiem powinien być filozof. Kiedy będziesz miał wszystko działające zdjęcie synchronizacji powinno dość szybko doprowadzić do zakleszczenia. Zakleszczenie nie powinno zatrzymywać samego programu, a tylko powodować że kolejne paint będą wciąż rysowały ten sam stan zmiennych programu (widelców, filozofów). Program powinien mieć opcję resetowania czyli skonstruowania na nowo stołu i filozofów. Dla lepszej wizualizacji każda operacja podniesienia, jedzenia itp. powinna zostać przedłużona (sleep) dla widocznej wizualizacji - ale tylko operacje, nie wizualizacje tych operacji. Konstruktor całej sceny lub poszczególnych elementów (stołu, filozofów) oraz metody podnoszące i odkładające widelec powinny mieć wywołanie repaint. Żadna inna część algorytmu nie powinna mieć żadnego styku z kodem rysującym bieżący stan na ekranie.

0

ok, zrobie na poczatku bez wizualizacji, ale i tak mam pomyslu jak ją zrobić.

0

mam synchronizować za pomoca oznaczenia "synchronized" czy za pomocą losowania widelca tak jak jest to opisane w tym linku co podałes ?

0

Synchronizacja czy też blokada (lock) ma na celu tylko jedno - wstrzymać wykonanie dostępu do danych do czasu aż inny wątek odblokuje te dane (wykona unlock lub wyjdzie z bloku/metody synchronizowanej).
Jedyne co trzeba synchronizować/blokować to operacje podnoszenia i odkładania widelca. Losowanie nie ma nic do tego. Algorytm, który jest na stronie, którą podałem to algorytm wątku dla każdego filozofa/gościa. Cały pozostały kod to zorganizowanie struktury danych dla widelców - czyli jakiejś tablicy/kolekcji, którą może zawierać stół. Wątków powinno być tyle ilu jest jedzących plus wątek Swing uruchomiony z wątku metody main(). Ten sam wątek wywołuje kod metody paint(). Oczywiście, o ile jest to samodzielny program.

0

zrobiłem tak:

import java.awt.Graphics;


import javax.swing.JPanel;


public class MPanel extends JPanel{
	Stol stol;
	
	public MPanel(){
		stol = new Stol();
		
		
	}

	
	protected void paintComponent(Graphics g) {
	}
	public void start(){
		stol.run();
	}
	

}
class Stol extends Thread{
	Widelec[] widelce;
	Gosc[] goscie;
	
	public Stol(){
		widelce = new Widelec[17];
		goscie = new Gosc[9];
		
		widelce[7] = new Widelec(300, 50, 550, 483);
		widelce[4] = new Widelec(550, 483, 50, 483);
		widelce[1] = new Widelec(50, 483, 300, 50);
		
		widelce[12] = new Widelec(300, 270, 375, 400);
		widelce[10] = new Widelec(375, 400, 220, 400);
		widelce[11] = new Widelec(220, 400, 300, 270);
		
		widelce[16] = new Widelec(300, 270, 300, 350);
		widelce[14] = new Widelec(300, 350, 220, 400);
		widelce[15] = new Widelec(300, 350, 375, 400);
		
		widelce[5] = new Widelec(300, 270, 300, 50);
		widelce[9] = new Widelec(375, 400, 550, 483);
		widelce[3] = new Widelec(220, 400, 50, 483);
		
		widelce[6] = new Widelec(340, 200, 300, 50);
		widelce[8] = new Widelec(340, 200, 550, 483);
		widelce[2] = new Widelec(340, 200, 50, 483);
		widelce[13] = new Widelec(340, 200, 300, 350);

		goscie[1] = new Gosc(widelce[1], widelce[2], widelce[3], widelce[4]);
		goscie[2] = new Gosc(widelce[1], widelce[5], widelce[6], widelce[7]);
		goscie[3] = new Gosc(widelce[7], widelce[8], widelce[9], widelce[4]);
		goscie[4] = new Gosc(widelce[3], widelce[11], widelce[14], widelce[10]);
		goscie[5] = new Gosc(widelce[10], widelce[15], widelce[12], widelce[9]);
		goscie[6] = new Gosc(widelce[16], widelce[11], widelce[12], widelce[5]);
		goscie[7] = new Gosc(widelce[13], widelce[14], widelce[15], widelce[16]);
		goscie[8] = new Gosc(widelce[2], widelce[13], widelce[6], widelce[8]);


	}
	
	public void run(){
		goscie[1].run();
		System.out.println("watek 1 uruchomiony !!!");
		goscie[2].run();
		System.out.println("watek 2 uruchomiony !!!");
		goscie[3].run();
		System.out.println("watek 3 uruchomiony !!!");
		goscie[4].run();
		System.out.println("watek 4 uruchomiony !!!");
		goscie[5].run();
		System.out.println("watek 5 uruchomiony !!!");
		goscie[6].run();
		System.out.println("watek 6 uruchomiony !!!");
		goscie[7].run();
		System.out.println("watek 7 uruchomiony !!!");
		goscie[8].run();
		System.out.println("watek 8 uruchomiony !!!");
	}

}
public class Gosc extends Thread{
	
	Widelec w1,w2,w3,w4;
	
	public Gosc(Widelec w1, Widelec w2, Widelec w3, Widelec w4){
		
		this.w1 = w1;
		this.w2 = w2;
		this.w3 = w3;
		this.w4 = w4;
		System.out.println("Gosc o nazwie " + this.getName() + " wlasnie dostal widelce");
	}
	
	public void run() {
		try {
			
			

			while(true){
				if(!w1.czyZajety()) w1.use(); else continue;
				if(!w2.czyZajety()) w2.use(); else {
					w1.putBack();
					continue;
				}
				if(!w3.czyZajety()) w3.use(); else {
					w1.putBack();
					w2.putBack();
					continue;
				}
				if(!w4.czyZajety()) w1.use(); else {
					w1.putBack();
					w2.putBack();
					w3.putBack();
					continue;
				}
				Thread.sleep(500);
				System.out.println("Gosc o nazwie " + this.getName() + " wlasnie zjadl");
				w1.putBack();
				w2.putBack();
				w3.putBack();
				w4.putBack();
				
			}

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
	}
		

}
	

import java.awt.Color;
import java.awt.Graphics;

class Widelec {
	int x1,y1,x2,y2;
	boolean stan;

	public Widelec(int x1, int y1, int x2, int y2){
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		stan = false;

	}
	public void use(){
		stan = true;
	}
	
	public void putBack(){
		stan = false;
	}
	public boolean czyZajety(){
		return stan;
	}
	
}

klasa stol dalej jest watkiem bo gdy nie byla to uruchamiala tylko pierwszy watek ktory w kolko dzialal.
Teraz to tez nie działa bo w kółko działa caly czas watek drugi i nie iwem czemu.

0

Po pierwsze w metodzie Stol.run() nie tworzysz żadnych wątków gości, lecz po prostu sekwencyjnie uruchamiasz ich metody run(). Skoro jednak każda z nich jest nieskończoną pętlą, to powinna uruchomić się tylko run() dla goście[1]. To pierwszy błąd.
Po drugie indeksy tablic w Javie podobnie jak w C i C++ zaczynają się od zera, a ostatnim elementem jest n-1. Traktowanie ich jakby miały indeksy 1..n to powód do popełniania błędów. Zwykle jest to naleciałość z Pascala.
Po trzecie nie mam pojęcia dlaczego u Ciebie gość operuje 4 widelcami zamiast dwoma. Czyżby Ci filozofowie to jacyś mutanci? :)
Po czwarte - stół tylko dziedziczy po Thread, ale wywołujesz jego metodę run(), czyli i tak z jego właściwości wątku w ogóle nie korzystasz.
Po piąte - gość nie ma dostawać widelców do ręki bo gdyby każdy miał parę widelców (a tym bardziej 4 szt.), to wszyscy zaczęliby jeść w tym samym momencie bo każdy miałby swój osobisty komplet. Widelce mają być na stole, a każdy gość ewentualnie może je użyć pod warunkiem, że ani lewego, ani prawego nikt nie używa.

Najlepiej narysuj sobie tych gości przy okrągłym stole i te widelce. To Ci ułatwi zrozumienie zadania.
Przeczytaj też dokumentację klasy Thread bo nie rozumiesz w ogóle pojęcia wątków. Dla ułatwienia podpowiem, że wątek to jakby osobny komputer (maszyna Turinga) działający na tej samej pamięci (stąd problem zakleszczeń). Stworzenie wątku polega na zdefiniowaniu metody run(), którą uruchomi utworzony w systemie wątek (dla JVM jest to jeszcze bardziej skomplikowane), a nie ty.

Utworzenie wątków gości wywołuje się przez:
goscie[n].start();
dla n od pierwszego do ostatniego gościa.
Liczba widelców dla 8 gości, to 8, a nie 17. Przy 17 problem prawie nie istnieje ponieważ tylko jeden widelec na cały stół będzie współdzielony przez dwóch gości. A w zadaniu współdzielony ma być KAŻDY widelec.

0

ehheheh w tym programie chodzi o to ze filozofów jest 8miu i kazdy z nich ma 4 ręce (4 widelce) :)
czyli widelców jest 16 :)

zrobiłem tak jak mówiłes u mnie kazdy widelec ma zmienna boolean stan która mowi czy dany widelec jest wykorzystywany czy nie.
i zanim jakis watek bedzie chcial podniesc widelec to sprawdza czy przypadkiem on nie jest podniesiony.

w metodzie stol.run nie tworze watkow tylko je włanczam, jak właczyć je wszystkie naraz ?

0

To trochę komplikuje kwestię zrozumienia działania i w szczególności sprawę wyrysowania tego na ekranie. Mozna to więc sobie wyobrazić jako szwedzki stół, gdzie jest 16 widelców do zabrania z koszyka przez 8 czteroręcznych gości. Ci, którym nie starczy 4 widelców będą musieli stać przy koszyku i warować na odniesione widelce, a Ci, którzy skończyli jeść będą musieli odnieść swój komplet do koszyka.
Alternatywą jest powiązanie gości z miejscami "stacjonowania" widelców na stole (podobnie jak dla 2 widelców), co jest moim zdaniem koncepcją wariata bo nijak się nie wiąże z kształtem stołu.
Dla mnie to jednak trochę głupie. Nic nie pomaga w zrozumieniu wątków, a niepotrzebnie komplikuje. Wizualizacja koncepcji wariata, to byłby jakiś programowy koszmar bo trzeba by najpierw ściśle określić do których widelców który gość może sięgnąć.

Co do Stołu, to nie możesz "włączać" wątków bo włączenie pierwszego z nich blokuje możliwość włączenia kolejnego itd. Przecież metoda run() każdego gościa jest nieskończona...
Ty potrzebujesz uruchomienie każdego gościa równolegle i równocześnie. Taką możliwość daje tylko odpalanie start dla każdego gościa. Przy okazji napis o uruchomieniu wątków zwyczajnie Cię okłamuje. Ta informacja powinna być odpalana na początku metody run gościa. A numer gościa powinien trafiać do jego konstruktora. Inaczej wątek będzie musiał być identyfikowany przez systemowy/JVM numer wątku, która to informacja nic Ci nie mówi (chyba, że powiążesz numer wątku z numerem gościa - tyle, że to bez sensu skoro od razu można użyć numeru gościa).

0

stol jest trójwymiarowy :) i wyglada tak:

user image

co bardzo pomaga wyobrazenie sobie problemu oraz jego odrysowania.

wydawało mi się że po odpaleniu metody run wątki zaczna dzielić sie procesorem.
Zapomniałem ze to trzeba zrobić metodą start.

--------------------------EDIT------------------------------------

Pomijając wizualizacje wszystko już działa. Teraz chciałbym jakos usprawnić jedzenie tych filozofów aby kazdy równomiernie sie najadał.
na razie moja metoda Gosc.run() wyglada tak:

public class Gosc extends Thread{
	
	int numer;
	Widelec w1,w2,w3,w4;
	int mojLicznik = 0;
	public Gosc(int numer, Widelec w1, Widelec w2, Widelec w3, Widelec w4){
		this.numer = numer;
		this.w1 = w1;
		this.w2 = w2;
		this.w3 = w3;
		this.w4 = w4;
		System.out.println("Gosc o numerze [" + numer + "] wlasnie dostal widelce");
	}
	
	public void statystyka(){
		System.out.println("STATYSTYKA GOSCIA NR [" + numer + "]: " +  (double)(mojLicznik/Stol.licznik));
	}
	
	public void run() {
		try {
			System.out.println("watek nr [" + numer + "] uruchomiony !!!");
			

			while(Stol.licznik < 10){
				System.out.println("watek nr [" + numer + "] złapał za pierwszy widelec !! !!!");
				if(!w1.czyZajety()) w1.use(); else {
					System.out.println("watek nr [" + numer + "] odlozyl widelce !! !!!");
					continue;
					
				}
				if(!w2.czyZajety()) w2.use(); else {
					w1.putBack();
					System.out.println("watek nr [" + numer + "] odlozyl widelce !! !!!");
					continue;
				}
				System.out.println("watek nr [" + numer + "] złapał za drugi widelec !! !!!");
				if(!w3.czyZajety()) w3.use(); else {
					w1.putBack();
					w2.putBack();
					System.out.println("watek nr [" + numer + "] odlozyl widelce !! !!!");
					continue;
				}
				System.out.println("watek nr [" + numer + "] złapał za trzeci widelec !! !!!");
				if(!w4.czyZajety()) w1.use(); else {
					w1.putBack();
					w2.putBack();
					w3.putBack();
					System.out.println("watek nr [" + numer + "] odlozyl widelce !! !!!");
					continue;
				}
				Thread.sleep(500);
				mojLicznik++;
				Stol.licznik++;
				System.out.println("Gosc o numerze [" + numer + "] wlasnie zjadl jest to jego " + mojLicznik + " raz " + "a ogolnie " + Stol.licznik);
				w1.putBack();
				w2.putBack();
				w3.putBack();
				w4.putBack();
				
				
			}

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
	}
		

}

Czy mógłbym jakoś użyć mechanizm synchronizacji z javy ?
Albo zrobić tak aby kazdy gość losowo łapał za widelce tylko nie wiem czy to w tym wypadku usprawni działanie programu.

0

Skoro krawędzie reprezentują widelce, a kulki gości, to musisz je sobie ponumerować i wpakować do jakiejś tablicy powiązania między nimi tak aby tylko dwóch gości mogło podnosić i odkładać dany widelec. Reszta taka sama jak przy problemie z dwoma widelcami.
Przy podnoszeniu widelców musisz próbować podnieść ich 4 zamiast lewego i prawego, a każde nieudane podniesienie musi skutkować odłożeniem już podniesionych.

0
Olamagato napisał(a)

Skoro krawędzie reprezentują widelce, a kulki gości, to musisz je sobie ponumerować i wpakować do jakiejś tablicy powiązania między nimi tak aby tylko dwóch gości mogło podnosić i odkładać dany widelec. Reszta taka sama jak przy problemie z dwoma widelcami.

Tak mam zrobione

Olamagato napisał(a)

Przy podnoszeniu widelców musisz próbować podnieść ich 4 zamiast lewego i prawego, a każde nieudane podniesienie musi skutkować odłożeniem już podniesionych.

To tez zrobiłem

Można coś jeszcze poprawić (za pomoca synchronized) ?

0

use() i putBack() powinny mieć modyfikator synchronized, albo ręcznie blokować za pomocą obiektów Lock.
Ważne, żeby rozumieć co powoduje użycie tego modyfikatora na metodzie lub jako blok. Otóż na początku bloku sprawdzany jest poziom blokady i jeżeli jest on większy niż zero, to następuje zatrzymanie wątku w oczekiwaniu na zmniejszenie się poziomu blokady do zera. Następnie kiedy jest już zerowy, to następuje wejście do bloku synchronizowanego i podniesienie blokady o 1. Jeżeli zdarzy się, że ten sam wątek jeszcze raz odpali synchronizowany blok dla tego samego obiektu to blokada znowu jest podnoszona o 1. W ten sposób inne wątki muszą czekać aż blokada zostanie zwolniona całkowicie.

Losowanie pierwszego podnoszonego widelca jest bardzo ważne bo inaczej łatwo doprowadzić do zakleszczenia. Kolejna rzecz - nie powinieneś sprawdzać czy widelec jest wolny bo w ułamku sekundy między sprawdzeniem, a użyciem widelec może stać się zajęty. Przecież w tym czasie inny wątek konkuruje o ten sam widelec. Czekaniem na dostęp zajmuje się właśnie metoda synchronizowana, która nie dopuści do uruchomienia swojego kodu, aż inny wątek nie wyjdzie z jakiejś metody synchronizowanej dotyczącej tego samego obiektu (tutaj obiektu konkretnego widelca).
No i na koniec - użycie metod print wywoływanych wprost z metod wątków
powoduje, że metody te konkurują ze sobą wzajemnie o dostęp do bufora urządzenia znakowego, które pozwala wyświetlić teksty na ekranie. Inaczej mówiąc one zatrzymują działanie wątków gości aż nie wygrają konkurencji o wysłanie tekstu do bufora znakowego. Należy je usunąć żeby program działał prawidłowo. Tak jak wcześniej pisałem kod wątków w żaden sposób nie może samoistnie wizualizować swojego stanu. To jest zadanie wątku Swing (lub innego), który ma te dane w kółko odczytywać i wyrysowywać na ekranie lub drukować na konsoli.

ps. A jeszcze co do włączania wątków równocześnie, to nie da się tego zrobić Thread.start() zapoczątkowuje wątek - czyli w miejscu wywołania rozdziela wątki na dwa różne (dotychczasowy oraz ten utworzony), kolejne wywołanie Thread.start() znowu rozdziela wątki - i tak aż utworzy się wszystkie. Można to zrobić np. w pętli for. Moment utworzenia wszystkich wątków nigdy nie może być zupełnie równoczesny bo wszystkie startują z jednego wątku, ale kiedy wszystkie się odpalą, to będą już działać równocześnie. Różnica czasu uruchomienia między nimi będzie wynosiła maksymalnie kilkadziesiąt taktów procesora.

0

no dobra, ale teraz jak napisać funkcje Widelec.use() bo moja wersja nic nie ma wspolnego z tym o czym Ty mowisz.

	synchronized public void use(){
		stan = true;
	}
	
	synchronized public void putBack(){
		stan = false;
	}
0

juz sobie poradziłem ze wszystkim, został mi tylko jeden problem, zatrzymywanie i resetowanie programu, staram się cos wykomibnować ale wyglada na to że musze konstruktory wątków jeszcze raz odpalać.

0

Zgadza się. Przyczyna jest choćby taka, że próba odpalenia metody start na zakończonym wątku powoduje zawsze wyjątek. Wątki trzeba więc konstruować zawsze od nowa, a to oznacza, że od nowa najlepiej skonstruować wszystko, a zakończoną wersję wykosić choćby przez przypisanie referencjom null (potrzebne czasem tylko w systemach z żuleniem pamięci).

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