Uruchamianie kodów w wątkach i kończenie wątków

0

Witam.
Chciałbym prosić o jakieś wskazówki do poniższego zadania:

"Zbudować klasę Letters, która posłuży do równoleglego uruchamiania kodów, wypisujących co sekundę litery podane w napisie przekazanym do konstruktora klasy.
Po stworzeniu obiektu klasy Letters w metodzie main(...) klasy Main wystartować wszystkie wątki, w których mają być wypisywane podane litery.
Po wstrzymaniu działania metody main(...) na 5 sekund - zakończyć działanie wszystkich kodów, wypisujących litery.

Uruchomienie poniższego programu:

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());
        /*<- tu uruchomić 
             wszystkie kody w wątkach 
         */

        Thread.sleep(5000);

        /*<- tu trzeba zapisać
           fragment, który kończy działanie kodów, wypisujących litery 
        */
        System.out.println("\nProgram skończył działanie");
      }

    }

powinno (w tej postaci) wypisać:
Thread A
Thread B
Thread C
Thread D

(po 5 sekundach)
Program skończył działanie

Natomiast po uzupełnieniu kodu w miejscah wskazanych przez /*<- */ - coś w rodzaju:

Thread A
Thread B
Thread C
Thread D
ACDBDBACACDBCBDA
Program skończył działanie.

Uwaga 1: modyfikacje klasy Main są dopuszczalne tylko w miejscach wskazanych przez /*<- */
Uwaga 2: nie wolno stosować System.exit
Uwaga 3: warto przy definiowaniu metody run() zastosować lambda-wyrażenie.

Mój obecny kod:

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());
    //Wyrażenie lambda
	(letters.getThreads()).forEach((t) -> t.start());

    Thread.sleep(5000);

    for (Thread t : letters.getThreads()){
    	t.interrupt();
    }
    System.out.println("\nProgram skończył działanie");
  }

}
import java.util.ArrayList;

public class Letters extends Thread {
	ArrayList<Thread> threads = new ArrayList<Thread>();
	
	public Letters(){}
	public Letters(String s){
		for(int i = 0; i < s.length(); i++){	
			threads.add(new Thread("Thread " + s.substring(i, i+1)));
		}
	}
	public ArrayList<Thread> getThreads(){
		return threads;
	}
	public void run(){
		while(true){
			try{
				System.out.print(this.getName());
				Thread.sleep(1000);
			} catch (InterruptedException ie){
				System.out.println("Wątek przerwany");
			}
		}
		
	}
}

Program nie odpala przeciążonej metody run() z klasy Letters bo w liście znajdują się obiekty klasy Thread, przez co nie wypisuje tych liter.
Pomoże ktoś?

0

Z tego co widzę na szybko:
Masz nadpisaną metodę run() w klasie Letters, którą myślisz, że uruchamiasz. Tak naprawdę uruchamiasz metody wątków, które sobie stworzyłeś w polu Threads, a te w domyśle są puste. Żeby ci to działało zrób klasę, która rozszerza Thread tak jak to zrobiłeś i tam wrzuć metodę run(), którą masz w Letters, a Letters niech będzie tylko klasą, która przechowuje kolekcję klas, którą utworzyłeś (te rozszerzające Thread).

0

Działa już :)

public Letters(String s){
		for(int i = 0; i < s.length(); i++){
			String letter = s.substring(i, i+1);
			threads.add(new Thread("Thread " + letter){
				public void run(){
					while(true){
						try{
							System.out.print(letter);
							Thread.sleep(1000);
						} catch (InterruptedException ie){
							break;
						}
					}	
				}
			});
		}
	}

W zadaniu jest napisane, że warto przy definiowaniu metody run() zastosować lambda-wyrażenie. Wie ktoś jak to można zrobić?

0
Runnable byleco= () -> { Zawartość metody run };
new Thread(byleco).start();
0
import java.util.ArrayList;

public class Letters extends Thread {
	ArrayList<Thread> threads = new ArrayList<Thread>();
	
	public Letters(){}
	public Letters(String s){
		for(int i = 0; i < s.length(); i++){
			String letter = s.substring(i, i+1);
//			threads.add(new Thread("Thread " + letter){
//				public void run(){
//					while(true){
//						try{
//							System.out.print(letter);
//							Thread.sleep(1000);
//						} catch (InterruptedException ie){
//							break;
//						}
//					}	
//				}
//			});
			Runnable myThread= () -> {
				while(true){
					try{
						System.out.print(letter);
						Thread.sleep(1000);
					} catch (InterruptedException ie){
						break;
					}
				}
			};
			threads.add(new Thread(myThread, "Thread " + letter));
		}
	}
	public ArrayList<Thread> getThreads(){
		return threads;
	}
	
}

Może tak być? Które rozwiązanie jest lepsze waszym zdaniem? Klasa anonimowa czy lambda wyrażenie?

0

Mam problem z kolejnym zadaniem. Mógłby ktoś pomóc?
Treść zadania:
Zbudować klasę StringTask, symulująca długotrwałe obliczenia, tu polegające na konkatenacji napisow.
Konstruktor klasy otrzymuje jako argument napis do powielenia oraz liczbę oznaczającą ile razy ten napis ma być powielony.
Klasa winna implementować interfejs Runnable, a w jej metodzie run() wykonywane jest powielenia napisu, przy czym to powielenia ma się odbywac za pomoca operatora '+' stosowanego wobec zmiennych typu String (to właśnie długotrwała operacja). Użycie '+' jest warunkiem obowiązkowe.

Obiekt klasy StringTask traktujemy jako zadanie, które może się wykonywać równolegle z innymi.
Możliwe stany zadania to:

CREATED  - zadanie utworzone, ale nie zaczęło się jeszcze wykonywać,
RUNNING - zadanie się wykonuje w odrebnym wątku
ABORTED - wykonanie zadania zostało przerwane
READY - zadanie zakończyło się pomyślnie i sa gotowe wyniki.

W klasie StringTask zdefiniować metody:

  public String getResult()  - zwracającą wynik konkatenacji
  public TaskState getState()  - zwracającą stan zadania
  public void start() - uruchamiającą zadanie w odrębnym watku
  public void abort() - przerywającą wykonanie kodzu zadania i działanie watku
  public boolean isDone()  - zwracająca true, jeśli wykonanie zadania się zakończyło normalnie lub przez przerwanie, false w przeciwnym razie

Poniższy kod program:

public class Main {

  public static void main(String[] args) throws InterruptedException {
    StringTask task = new StringTask("A", 70000);
    System.out.println("Task " + task.getState());
    task.start();
    if (args.length > 0 && args[0].equals("abort")) { 
    /*<- tu zapisać kod  przerywający działanie tasku po sekundzie 
         i uruchomic go w odrębnym wątku
    */
    }
    while (!task.isDone()) {
      Thread.sleep(500);
      switch(task.getState()) {
        case RUNNING: System.out.print("R."); break;
        case ABORTED: System.out.println(" ... aborted."); break;
        case READY: System.out.println(" ... ready."); break;
        default: System.out.println("uknown state");
      }
      
    }
    System.out.println("Task " + task.getState());
    System.out.println(task.getResult().length());
  }

}

uruchominy bez argumentu powinien wyprowadzić coś w rodzaju:
Task CREATED
R.R.R.R.R.R.R.R.R. ... ready.
Task READY
70000

a uruchomiony z argumentem "abort" może wyprowadzić:
Task CREATED
R. ... aborted.
Task ABORTED
31700

Uwaga 1. Plik Main.java może być modyfikowany tylko w miejscu oznaczonym /*<- */
Uwaga 2. Nie wolno uzywac metody System.exit(...)

Mój kod:

public class StringTask  implements Runnable{
    private String word;
    private int nr;
    private String result = "";
    volatile String state="";
    private boolean done = false;
    private boolean end = false;
   
    public StringTask(){
        this.state = "ABORTED";
    }
    public StringTask(String s,int n){
        this. word = s;
        this.nr= n;
        this.state = "CREATED";
    }
    public void run(){
    this.state="RUNNING";
    synchronized(this.result){
    try{
        for(int i = 0; i <nr; i++){
            result += word; 
        }
        this.state = "READY";
        this.done = true;
    }
        catch(Exception e) {
            this.state = "ABORTED";
            this.done = false;
        }
    }
    }    
    public void start(){
    	Thread thread = new Thread(this);
        thread.start();
    }
    public void abort() throws Throwable{
        this.end = true;
        this.done= true;
        this.state = "ABORTED";
        this.finalize();
       
    }
    public String getResult(){
        return this.result;
    }
    public String getState(){
        return this.state;
    }
    public boolean isDone(){
        return this.done;
    }
}

W miejscu switch case pokazuję błąd, RUNNING, ABORTED i READY nie są zmiennymi. Gdy wezmę je w cudzysłów wszystko działa ale poleceniu jest napisane: "Plik Main.java może być modyfikowany tylko w miejscu oznaczonym /*<- */"

0

Pomoże ktoś?

0

stwórz sobie enum States { ABORTED etc. }

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