Poprawne zsynchronizowanie metod

0

Mam oto taki kod:

import javax.swing.*;

class SomeThread extends Thread {

  volatile boolean stopped = false;
  volatile boolean suspended = false;

  public void run() {

    double d = 0;
    while(!stopped) {
      try {
        synchronized(this) {
          while (suspended) wait();
        }
      } catch (InterruptedException exc) {
          System.out.println("Obsluga przerwania watku w stanie wait");
          System.out.println("Co powie isInterrupted() ?: "+ isInterrupted());
      }
      if (suspended) System.out.println("Watek wstrzymany na wartosci " + d);
      else System.out.println(++d);
    }
  }

  public void stopThread() {
    stopped = true;
  }

  public void suspendThread() {
    suspended = true;
  }

  public void resumeThread() {
    suspended = false;
    synchronized(this) {
      notify();
    }
  }

}

public class ActionsOnThread {
	
  public static void main(String args[]) {
    String msg = "I = interrupt\n" +
                 "E = end\n" +
                 "S = suspend\n" +
                 "R = resume\n" +
                 "N = new start";

    SomeThread t = new SomeThread();
    t.start();
    String cmd;
    while ((cmd = JOptionPane.showInputDialog(msg)) != null) {
      char c = cmd.charAt(0);
      switch (c) {
        case 'I' : t.interrupt(); break;
        case 'E' : t.stopThread(); break;
        case 'S' : t.suspendThread(); break;
        case 'R' : t.resumeThread(); break;
        case 'N' : if (t.isAlive())
                     JOptionPane.showMessageDialog(null, "Thread alive!!!");
                   else {
                     t = new SomeThread();
                     t.start();
                   }
                   break;
        default  : break;
      }
      JOptionPane.showMessageDialog(null,
                  "Command " + cmd + " executed.\n" +
                  "Thread alive  ? " + (t.isAlive() ? "Y\n" : "N\n") +
                  "Thread interrupted ? " + (t.isInterrupted() ? "Y\n" : "N")
                  );
    }
    System.exit(0);
  }
}

Jak poprawnie zsynchronizować isInterrupted() w klasie głównej aby po podaniu komend S oraz I dawało odpowiedź N (co jest prawdą)?

0

Nie do końca zrozumiałem ostatniego zdania.
Wiec tak, interrupt ustawia Ci flagę w wątku - musisz sprawdzać czy została ona ustawiona. Dwie metody interrupter() isInterrupted(). Pierwsza zwróci flagę i ustawi ją na 0 druga tylko zwróci flage. Możesz to robić w tym samym miejscu w którym sprawdzasz !stopped(a więc główny while)

stopThread i suspend thread można zrobić jako metody syncronizowane. resumeThread też zrób jako synchornizowaną metodę i będzie można usunąć blok synchronizacji;
umm jeszcze nie powinno tam raczej być while(suspend) wait() bo to może doprowadzić do deadlocka np kiedy zrobisz interrupt to i tak wątek siedzi w wait i bedzie czekał na resume pomimo wcześniejszego notify.

AA to to w ostatnim to sekwencja jest tak ?.
No to isInterrupt do głównego while(), drugi while zmień na if do stop thread dodaj też notyfy;
Po wybraniu I przez, również musisz posłać notyfy() bo inaczej nie będzie reakcji na dalsze zmiany dopóki nie wybudzisz tego wątku.

EDIT:
A nie czekaj trochę za szybko - jak dasz interrupt() kiedy wątek jest w wait() powinno wywalić wyjątkiem. Możesz to po prostu obsłużyć (no ale jak wcześniej dasz notyfy to też będzie działać:))

0

Dziękuję za odpowiedź.

Nie pomogło mi to jednak w problemie.
Chodzi mi o to, że jak odpalam program i podaję sekwencję S (suspended) - czyli wywołuję wait()... a następnie: I (interrupt) to wyrzucany jest wyjątek na konsolę gdzie jest napisane że wątek nie jest już interrupted (false) (i tak powinno być), ale również pojawia się JOptionPane.showMessageDialog w którym jest sprawdzny isInterrupted i tam jest już Y (true).
Problem właśnie tkwi w odpowiednim zsynchronizowaniu sprawy. Próbowałem przeciążać interrupt() ale to też nic nie daje ;/

No chyba, że nie do końca zrozumiałem Twój post.

0

No dobra, więc tak - sprawa jest o tyle dziwna, że nie mam pojęcia dlaczego w dialogu isInterrupted() jest true - nie wiem gdzie się ta flaga ustawia, bo generalnie powinna być false.

Edit. właśnie mnie olśniło. Rozwiązanie jest banalne ;P Twój problem polega na tym, że główny wątek programu wykonuje się "szybciej" niż wątek który tworzysz. Także najpierw wywołana jest metoda interrupt() która jest niejako żądaniem przerwania wątku - to żądanie obsługiwane jest przez sam wątek który ma być przerwany, jednak flagę ustawia wątek wywołujący. Tak więc, wywołujesz metodę interrupt(), główny wątek biegnie sobie dalej, wpada w dialog, odczytuje flagę, ta została ustawiona przed chwilą na true - bo rozpoczęto przetwarzanie żądania, które w międzyczasie wywala wyjątek, w trakcie obsługi którego flaga ta jest czyszczona i przy powrocie sterowania do twojego bloku catch jest już ona wyczyszczona!. Cała filozofia ;P:P
To są uroki programowania równoległego właśnie :)

Workarounderm na to jest wstawienie takiego bloku z opóźnieniem, na obsługę komendy I

      switch (c) {
        case 'I' : 
        	{
        		t.interrupt();
        		Thread.sleep(50);
        		break;
        	}
        			

Dowód na to że ustawianie flagi jest wykonane w wątku wywołującym

//klasa Thread
  927       public void interrupt() {
  928           if (this != Thread.currentThread())
  929               checkAccess();
  930   
  931           synchronized (blockerLock) {
  932               Interruptible b = blocker;
  933               if (b != null) {
  934                   interrupt0();           // Just to set the interrupt flag
  935                   b.interrupt(this);
  936                   return;
  937               }
  938           }
  939           interrupt0();
  940       }
  941   

Oraz przyczyna dla którego w bloku catch flaga jest wyczyszczona

//Klasa Object
  375        * @exception  InterruptedException if any thread interrupted the
  376        *             current thread before or while the current thread
  377        *             was waiting for a notification.  The <i>interrupted
  378        *             status</i> of the current thread is cleared when
  379        *             this exception is thrown.

Myślę, że opisałem zagwozdkę wystarczająco jasno :)

0

Dziękuję Ci dobry człowieku za rzeczowe wyjaśnienie sprawy!

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