Jak zdeklarować metodę run()

0

Mój problem to zdeklarowanie metody run() w klasie Letters (ta klasa ma służyć do równoległego uruchamiania kodów, które będą wypisywały co jakiś czas określone litery). Oczekiwany efekt ma wyglądać tak:
Wątek A
Wątek B
Wątek C
Wątek D
BDACADCBADCBBCDABCDA
Program skończył działanie

Klasa Main:

public class Main {
	  public static void main(String[] args) throws InterruptedException {
	    Letters letters = new Letters("ABCD");
	    for (Thread t : letters.getThreads()) System.out.println(t.getName());
	    for (Thread t : letters.getThreads()) t.start();
	    Thread.sleep(5000);
	    for (Thread t : letters.getThreads()) t.interrupt();
	    System.out.println("\nProgram skończył działanie");
	  }
	}

W klasie Letters mam coś takiego:

import java.util.ArrayList;
public class Letters extends Thread {
	ArrayList<Thread> listaWatkow = new ArrayList<Thread>();
	public Letters (String m) {
		for (int i = 0; i < m.length(); i++) {
			String litera;
			litera = m.substring(i, i+1);
			listaWatkow.add(new Thread ("Wątek " + litera));
			}
	}
	
	public void run() {
		while (!Thread.interrupted()) {
			try {
				????????
				}
			catch (Exception exc) {
				return;
				}
		}
	}
	
	public ArrayList<Thread> getThreads() {
		return listaWatkow;
	}
}

Czy jest jakiś inny sposób zakończenia wątków wypisujących litery niż przez metodę interrupt()?

0

Ładniejszą praktyką jest zrobienie własnego interrupta -> robisz w tym wątku pole boolean które cyklicznie sprawdzasz w run() i masz metodę która ustawia wartość tego booleana. Jak chcesz przerwać wątek to ustawiasz wartość i już.

0

Własnego interrupta wymyśliłem i (po sprawdzeniu w innym programie) mogę powiedzieć, że działa :)
Natomiast cały czas mam problem z metodą run(). Możecie coś podpowiedzieć?

0

Ale podpowiedzieć co konkretnie? Bo teraz w ogóle źle to zrobiłeś. Letters ma nie być Wątkiem. Masz mieć jakąś inną klasę Thread/Runnable której zadaniem jest wypisywanie jednej literki. Letters tworzy N takich obiektów a potem je startuje / stopuje.

0

No nie da się ukryć, że ze zrozumieniem u mnie tekstu czytanego nie zawsze jest najlepiej :)
Dzięki za takie brutalne wskazanie błędu!

Wygląda, że wszystko udało się rozwiązać, ale jeden problem pozostał. Autor zadania oczekuje takiego rezultatu:
Thread A
Thread B
Thread C
Thread D
ACDBDBACACDBCBDA
Program skończył działanie.

A mój program po napisie "Program skończył działanie" wyświetla jeszcze jakieś litery - np. tak:
Thread A
Thread B
Thread C
Thread D
CABDCBADBACDACBDCBAD
Program skończył działanie
ACB

Klasa Main:

public class Main {

	public static void main(String[] args) throws InterruptedException {
		Letters letters = new Letters ("ABCD");
		for (Thread t : letters.getThreads()) System.out.println(t.getName());
			
		for (String x : letters.getNazwa()) {
			Watek a = new Watek (x);
			Thread newThrd = new Thread(a);
			newThrd.start();
		}
				
		Thread.sleep(5000);
		
		Watek.zakoncz = true;
		
		System.out.println("\nProgram skończył działanie");

	}

}

Klasa Letters:

import java.util.ArrayList;

public class Letters {

	static ArrayList<Thread> listaWatkow = new ArrayList<Thread>();
	static ArrayList<String> nazwaWatku = new ArrayList<String>();
	
	public Letters (String m) {
		for (int i = 0; i < m.length(); i++) {
			String litera;
			litera = m.substring(i, i+1);
			listaWatkow.add(new Thread ("Thread " + litera));
			nazwaWatku.add(litera);
			}
	}
	
	public ArrayList<Thread> getThreads() {
		return listaWatkow;
	}
	
	public ArrayList<String> getNazwa() {
		return nazwaWatku;
	}
	
}

Klasa Watek:

public class Watek implements Runnable {

	String thrdName;
	static boolean zakoncz = false;
	
	Watek (String nazwa) {
		thrdName = nazwa;
	}
	
	@Override
	public void run() {
		
		while (zakoncz == false) {
		try {
			Thread.sleep(1000);
			System.out.print(thrdName);
		}
		catch (InterruptedException exc) {
			System.out.println("Wątek został przerwany");
		}
		}
	}
	
}

Czy czegoś jeszcze nie widzę?
No i czy nie przekombinowałem za bardzo tego rozwiązania?

0

Jejku, jej! Patrz co robisz. Masz:

  1. Sprawdzenie warunku.
  2. Sleep.
  3. Wypisanie.

Co sie stanie jeśli w trakcie sleepa zrobisz zabicie wątku? Ano sleep dojdzie do końca, WYPISZESZ LITERKĘ, sprawdzisz znów warunek i zakończysz wątek. Klasyczny błąd "check-then-act" czyli sprawdzasz warunek a potem wykonujesz akcję, podczas gdy "w międzyczasie" warunek mógł sie zmienić.

0

no jasne!
dzięki jeszcze raz.
Dodałem if-a przed wypisywaniem litery sprawdzającego stan zmiennej 'zakoncz' i teraz jest OK, czyli ostatecznie klasa Watek wygląda tak:

public class Watek implements Runnable {

	String thrdName;
	static boolean zakoncz = false;
	
	Watek (String nazwa) {
		thrdName = nazwa;
	}
	
	@Override
	public void run() {
		
		while (zakoncz == false) {
		try {
			Thread.sleep(1000);
			if(zakoncz == false) System.out.print(thrdName);
		}
		catch (InterruptedException exc) {
			System.out.println("Wątek został przerwany");
		}
		}
	}
	
}
0

Wystarczyłoby pewnie u ciebie wypisywać literkę PRZED sleepem i if nie byłby potrzebny ;) (tzn to nadal jest słaba synchronizacja ale w twoim kodzie zadziała).

0

Zmienna zakoncz musi być volatile, bo zapisujesz ją z innego wątku niż czytasz. Jeśli nie ma volatile, to JVM może tę zmienną trzymać w rejestrze i może się nigdy nie zmienić w czasie wykonywania pętli. Wtedy zdajesz się na łut szczęścia.

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