2012-10-20 17 views
10

mam 3 wątki 1st Drukowanie 2-ta druk B 3rd drukowania Curuchomione 3 wątki w sekwencji java

Chcę drukować w sekwencji ABCABCABC i tak dalej .....

Więc napisał poniższy program, ale nie jestem w stanie osiągnąć tego samego. Jestem świadomy problemu, że gdy status = 1 w tym czasie mówi na przykład wątek B1 i C1 oczekują i kiedy robię notifyAll() obu oczekujących wątku obudzić iw zależności od przydziału procesora może wydrukować B lub C.

w tym przypadku chcę wydrukować tylko B po A.

jakie modyfikacje muszę wykonać.

public class NotifyAllExample { 

    int status=1; 
    public static void main(String[] args) { 

     NotifyAllExample notifyAllExample = new NotifyAllExample(); 

     A1 a=new A1(notifyAllExample); 
     B1 b=new B1(notifyAllExample); 
     C1 c=new C1(notifyAllExample); 

     a.start(); 
     b.start(); 
     c.start(); 
    } 
} 

class A1 extends Thread{ 
    NotifyAllExample notifyAllExample; 

    A1(NotifyAllExample notifyAllExample){ 
     this.notifyAllExample = notifyAllExample; 
    } 

    @Override 
    public void run() { 

     try{ 
      synchronized (notifyAllExample) { 

       for (int i = 0; i < 100; i++) { 

        if(notifyAllExample.status!=1){ 
         notifyAllExample.wait(); 
        } 

        System.out.print("A "); 
        notifyAllExample.status = 2; 
        notifyAllExample.notifyAll(); 
       } 

      } 
     }catch (Exception e) { 
      System.out.println("Exception 1 :"+e.getMessage()); 
     } 

    } 

} 

class B1 extends Thread{ 

    NotifyAllExample notifyAllExample; 

    B1(NotifyAllExample notifyAllExample){ 
     this.notifyAllExample = notifyAllExample; 
    } 

    @Override 
    public void run() { 

     try{ 
      synchronized (notifyAllExample) { 

       for (int i = 0; i < 100; i++) { 

        if(notifyAllExample.status!=2){ 
         notifyAllExample.wait(); 
        } 

        System.out.print("B "); 
        notifyAllExample.status = 3; 
        notifyAllExample.notifyAll(); 
       } 

      } 
     }catch (Exception e) { 
      System.out.println("Exception 2 :"+e.getMessage()); 
     } 

    } 
} 


class C1 extends Thread{ 

    NotifyAllExample notifyAllExample; 

    C1(NotifyAllExample notifyAllExample){ 
     this.notifyAllExample = notifyAllExample; 
    } 

    @Override 
    public void run() { 

     try{ 
      synchronized (notifyAllExample) { 

       for (int i = 0; i < 100; i++) { 

        if(notifyAllExample.status!=3){ 
         notifyAllExample.wait(); 
        } 

        System.out.print("C "); 
        notifyAllExample.status = 1; 
        notifyAllExample.notifyAll(); 
       } 

      } 
     }catch (Exception e) { 
      System.out.println("Exception 3 :"+e.getMessage()); 
     } 

    } 
} 
+1

AMHO odpowiedzi są właściwe, ale można zoptymalizować ten kod z instancji: trzy klasy są to samo z wyjątkiem wartości literalnej statusu. Możesz dodać parametr, sugeruję executionOrder, aby miał tylko jedną klasę. Nadaj nazwę wątkowi za pomocą funkcji setName() lub super() i użyj jej w raporcie wyjątku. – Aubin

+0

prawda ... zoptymalizuję to ... dzięki Aubin. – Jayesh

Odpowiedz

8

Konwersja tych IF do sprawozdania natomiast aby uzyskać pożądany zachowanie:

if (notifyAllExample.status != 2){ 
    notifyAllExample.wait(); 
} 

do

while (notifyAllExample.status != 2){ 
    notifyAllExample.wait(); 
} 

Zapewni to, że jeśli gwint zostaje powiadomiony, że nie będzie wychodzić z dopóki pętla nie osiągnie wartości statusu.

Należy również oznaczyć wartość status jako zmienną, aby wątki nie miały kopii lokalnej.

+0

o tak ..... Popełniłem błąd w zrozumieniu instrukcji If i pętli while. – Jayesh

+0

Ponadto, jak wspomniałeś, aby oznaczyć status jako ulotny, w jaki sposób będzie to dla mnie korzystne? bez oznaczania go jako niestabilnego również uzyskuję pożądany rezultat. Teoretycznie wiem, co Volatile robi, ale nie praktycznie. Czy możesz mi wyjaśnić, w jaki sposób Java będzie traktować zmienną statusową bez wahania i niestabilności? – Jayesh

+0

bez lotnego słowa kluczowego w statusie umożliwia JVM optymalizację dostępu do zmiennej statusu poprzez posiadanie lokalnej kopii dla każdego wątku, co oznacza, że ​​zapisywanie przez inne wątki nie będzie widoczne. Określenie zmiennego słowa kluczowego uniemożliwiłoby takie optymalizacje, a każdy przeczytany odczytałby wartość według najnowszego zapisu. – Vikdor

0

Trzeba zastąpić

if (notifyAllExample.status!=1) 

z

while (notifyAllExample.status!=1) 

i to samo w innych 2 klas. Jeśli nie, to zaraz po wyjściu czekania wątek będzie kontynuowany, nie wiedząc, czy to jego kolej.

+0

Dzięki ... pomogło mi to. – Jayesh

0

Wymienić:

if(notifyAllExample.status!=1){ 
    notifyAllExample.wait(); 
} 

z:

while(notifyAllExample.status!=1){ 
    notifyAllExample.wait(); 
} 

we wszystkich klasach odpowiednio.

+0

Dzięki ... pomogło mi to. – Jayesh

4
public class RunThreadsInOrder implements Runnable { 

    static int numThread = 1; 
    static int threadAllowedToRun = 1; 
    int myThreadID; 
    private static Object myLock = new Object(); 

    public RunThreadsInOrder() { 
     this.myThreadID = numThread++; 
     System.out.println("Thread ID:" + myThreadID); 
    } 

    @Override 
    public void run() { 
     synchronized (myLock) { 
      while (myThreadID != threadAllowedToRun) { 
       try { 
        myLock.wait(); 
       } catch (InterruptedException e) { 

       } catch (Exception e) {} 
      } 
      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
      } 

      System.out.println("myThreadID is running: " + myThreadID); 
      myLock.notifyAll(); 
      threadAllowedToRun++; 
     } 
    } 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 

     Thread t1 = new Thread(new RunThreadsInOrder()); 
     Thread t2 = new Thread(new RunThreadsInOrder()); 
     Thread t3 = new Thread(new RunThreadsInOrder()); 
     Thread t4 = new Thread(new RunThreadsInOrder()); 
     Thread t5 = new Thread(new RunThreadsInOrder()); 
     Thread t6 = new Thread(new RunThreadsInOrder()); 
     Thread t7 = new Thread(new RunThreadsInOrder()); 

     t7.start(); 
     t6.start(); 
     t5.start(); 
     t4.start(); 
     t3.start(); 
     t2.start(); 
     t1.start(); 

    } 
} 
-1

Myślę, że łatwiej jest to osiągnąć przy użyciu sprzężenia. Przykład:

public static void main(String[] args) {  
    final Thread t1 = new Thread("t1") { 
     @Override 
     public void run() { 
      System.out.println("i am thread: " + Thread.currentThread().getName()); 
     } 
    }; 

    final Thread t2 = new Thread(t1, "t2") { 
     @Override 
     public void run() { 
      t1.start(); 
      try { 
       t1.join(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println("i am thread: " + Thread.currentThread().getName()); 
     } 
    }; 

    Thread t3 = new Thread(t2, "t3") { 
     @Override 
     public void run() { 
      t2.start(); 
      try { 
       t2.join(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println("i am thread: " + Thread.currentThread().getName()); 
     } 
    }; 

    t3.start(); 

}

+0

Czy możesz wyjaśnić, w jaki sposób wątek działa cyklicznie? – Visu

-1

Oto moje rozwiązanie spróbuj i daj mi znać

package thread; 

class SyncPrinter { 
    public static void main(String[] args) { 
     SyncPrinterAction printAction1 = new SyncPrinterAction(new int[]{1,5,9,13}, true); 
     SyncPrinterAction printAction2 = new SyncPrinterAction(new int[]{2,6,10,14}, true); 
     SyncPrinterAction printAction3 = new SyncPrinterAction(new int[]{3,7,11,15}, true); 
     SyncPrinterAction printAction4 = new SyncPrinterAction(new int[]{4,8,12,16}, false); 

     printAction1.setDependentAction(printAction4); 
     printAction2.setDependentAction(printAction1); 
     printAction3.setDependentAction(printAction2); 
     printAction4.setDependentAction(printAction3); 

     new Thread(printAction1, "T1").start();;   
     new Thread(printAction2, "T2").start(); 
     new Thread(printAction3, "T3").start();  
     new Thread(printAction4, "T4").start(); 



    } 
} 

class SyncPrinterAction implements Runnable { 

    private volatile boolean dependent; 
    private SyncPrinterAction dependentAction; 
    int[] data; 

    public void setDependentAction(SyncPrinterAction dependentAction){ 
     this.dependentAction = dependentAction; 

    } 

    public SyncPrinterAction(int[] data, boolean dependent) { 
     this.data = data; 
     this.dependent = dependent; 
    } 

    public SyncPrinterAction(int[] data, SyncPrinterAction dependentAction, boolean dependent) { 
     this.dependentAction = dependentAction; 
     this.data = data; 
     this.dependent = dependent; 
    } 

    @Override 
    public void run() { 
     synchronized (this) { 

      for (int value : data) { 

       try { 
        while(dependentAction.isDependent()) 
         //System.out.println("\t\t"+Thread.currentThread().getName() + " :: Waithing for dependent action to complete"); 
        wait(100); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 

       dependentAction.setDependent(true); 

       System.out.println(Thread.currentThread().getName() + " :: " +value); 
       dependent = false; 
      } 

     } 

    } 

    private void setDependent(boolean dependent) { 
     this.dependent = dependent; 

    } 

    private boolean isDependent() { 
     return dependent; 
    } 

} 
+0

Odpowiedzi na kodowanie zrzutu nie są przydatne dla innych czytelników, ponieważ nie wyjaśniają, co zmieniliście lub co próbowaliście wykazać. Dodaj wyjaśnienie. –

+0

Pomysł jest bardzo prosty: Jaki jest warunek oczekiwania dla każdej nitki? Dla wątku wątek 2: 1 powinien zostać wykonany jeden raz, zanim wątek 2 zostanie wykonany jeden raz. Wątek 3: 2 powinien zostać wykonany jeden raz, zanim wątek 3 zostanie wykonany jeden raz. i tak dalej jest tyle wątków. Dla wątku 2: n wątek powinien zostać wykonany jeden raz, zanim wątek 1 zostanie wykonany jeden raz. Oto sztuczka, którą powinniśmy zainicjować jako n-wątek wykonany tak, aby 1-nitka rozpoczynała się od 2 wątków i tak dalej. – Visu

0
public class Main { 
     public static void main(String[] args) throws IOException{ 
     Thread t1 = new Thread(new A(), "1"); 
     Thread t2 = new Thread(new A(), "2"); 
     Thread t3 = new Thread(new A(), "3"); 

     t1.start(); 
     try{ 
      t1.join(); 
     }catch (Exception e){ 

     } 
     t2.start(); 
     try{ 
      t2.join(); 
     }catch (Exception e){ 

     } 
     t3.start(); 
     try{ 
      t3.join(); 
     }catch (Exception e){ 

     } 


    } 
} 

    class A implements Runnable{ 
    public void run(){ 
     System.out.println(Thread.currentThread().getName()); 
    } 
} 

lub użyć Executor Framework

public class Sequence { 
    int valve = 1; 
    public static void main(String[] args){ 
     Sequence s = new Sequence(); 
     ExecutorService es = Executors.newFixedThreadPool(3); 

     List<Runnable> rList = new ArrayList<>(); 
     rList.add(new A(s)); 
     rList.add(new B(s)); 
     rList.add(new C(s)); 

     for(int i = 0; i < rList.size(); i++){ 
      es.submit(rList.get(i)); 
     } 
     es.shutdown(); 

    } 
} 

class A implements Runnable{ 
    Sequence s; 

    A(Sequence s){ 
     this.s = s; 
    } 

    public void run(){ 
     synchronized (s) { 
      for (int i = 0; i < 10; i++) { 
       while (s.valve != 1) { 
        try { 
         s.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println("A"); 
       s.valve = 2; 
       s.notifyAll(); 
      } 
     } 
    } 
} 

class B implements Runnable{ 
    Sequence s; 

    B(Sequence s){ 
     this.s = s; 
    } 

    public void run() { 
     synchronized (s) { 
      for (int i = 0; i < 10; i++) { 
       while (s.valve != 2) { 
        try { 
         s.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println("B"); 
       s.valve = 3; 
       s.notifyAll(); 
      } 
     } 
    } 
} 

class C implements Runnable{ 
    Sequence s; 

    C(Sequence s){ 
     this.s = s; 
    } 

    public void run() { 
     synchronized (s) { 
      for(int i = 0; i < 10; i++) { 
       while (s.valve != 3) { 
        try { 
         s.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println("C"); 
       s.valve = 1; 
       s.notifyAll(); 
      } 
     } 
    } 
} 

W pierwszy przypadek joi n dla każdego wątku powoduje, że wątki oczekują na siebie nawzajem.W drugim przypadku lista zapisuje wątki, a executor wykonuje je jeden po drugim tworząc 3 wątki. Innym sposobem wykonania tej czynności jest obecność tylko jednej działającej klasy, a komunikacja między wątkami odbywa się za pośrednictwem zmiennej statycznej w klasie głównej i zmienna w runnable klasy

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.Executor; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class Seq { 
    int i = 1; 
    public static void main(String[] args){ 
     Seq s = new Seq(); 
     Common c1 = new Common(s, 1); 
     Common c2 = new Common(s, 2); 
     Common c3 = new Common(s, 3); 

     List<Runnable> l = new ArrayList<>(); 
     l.add(c1); 
     l.add(c2); 
     l.add(c3); 

     ExecutorService es = Executors.newFixedThreadPool(3); 
     for(int i = 0; i < 3; i++){ 
      es.submit(l.get(i)); 
     } 
     es.shutdown(); 
    } 
} 

class Common implements Runnable{ 
    Seq s; 
    int o; 

    Common(Seq s, int o){ 
     this.s = s; 
     this.o = o; 
    } 

    public void run(){ 
     synchronized (s) { 
      for (int z = 0; z < 100; z++) { 
       if(s.i > 3) 
        s.i = 1; 
       while (s.i != o) { 
        try { 
         s.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println(o); 
       s.i++; 
       s.notifyAll(); 
      } 
     } 
    } 
} 
+1

Chociaż ten kod może odpowiedzieć na pytanie, podanie dodatkowego kontekstu dotyczącego * how * i/lub * dlaczego * rozwiązuje problem, poprawi długoterminową wartość odpowiedzi. - [Z recenzji] (http: // stackoverflow.com/review/low-quality-posts/13235994) –

0

zostałem poproszony o napisanie podobnego programu w rozmowie z dodatkowym warunkiem, że powinna ona być rozszerzalny w taki sposób, że możemy zapewnić naszym własnym liczbę wątków i należy je wydrukować znaki z pierwszą nitką drukującą "A", a następnie kolejnymi wątkami drukującymi B, C, D i tak dalej. Oto jak to zrobiłem.

public class AlternateCharPrinter { 

    public static char ch = 65; 

    private static void createAndStartThreads(int count) { 
     Object lock = new Object(); 
     for (int i = 0; i < count; i++) { 
      new Thread(new AlternateCharRunner((char) (65 + i), lock)).start(); 
     } 

    } 

    public static void main(String[] args) { 
     createAndStartThreads(4); 
    } 

} 

class AlternateCharRunner implements Runnable { 

    private char ch; 
    private Object lock; 
    private static int runnerCount; 

    public AlternateCharRunner(char ch, Object lock) { 
     this.ch = ch; 
     this.lock = lock; 
     runnerCount++; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      synchronized (lock) { 
       while (ch != AlternateCharPrinter.ch) { 
        try { 
         lock.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
       System.out.println(AlternateCharPrinter.ch++); 
       if (AlternateCharPrinter.ch == (65 + runnerCount)) { 
        AlternateCharPrinter.ch = 65; 
       } 
       lock.notifyAll(); 
      } 
     } 
    } 

} 
0

Najprostszym rozwiązaniem, aby rozwiązać ten może być następujący sposób:

public class PrintInOrder implements Runnable { 

private int valueToPrint; 
private int id; 
private static int turn = 1; 
private static int RESET_TURN_THRESHOLD = 3; 

public PrintInOrder() { 
    this.valueToPrint = -1; 
} 

public PrintInOrder(int id, int val) { 
    this.id = id; 
    this.valueToPrint = val; 
} 

@Override 
public void run() { 
     while(true) { 
      if (turn == this.id) { 
       System.out.println(Thread.currentThread().getName() + "::::" + valueToPrint); 
       turn++; 
      } 
      if (turn > RESET_TURN_THRESHOLD) { 
       turn = 1; 
      } 
     } 

} 

public static void main(String []args) { 
    Thread t1 = new Thread(new PrintInOrder(1, 1)); 
    t1.setName("THREAD-1"); 
    t1.start(); 
    Thread t2 = new Thread(new PrintInOrder(2, 2)); 
    t2.setName("THREAD-2"); 
    t2.start(); 
    Thread t3 = new Thread(new PrintInOrder(3, 3)); 
    t3.setName("THREAD-3"); 
    t3.start(); 
} 

}

/* 
OUTPUT:::: 
THREAD-1::::1 
THREAD-2::::2 
THREAD-3::::3 
THREAD-1::::1 
THREAD-2::::2 
THREAD-3::::3 
THREAD-1::::1 
THREAD-2::::2 
THREAD-3::::3 
THREAD-1::::1 
THREAD-2::::2 
THREAD-3::::3 
THREAD-1::::1 
THREAD-2::::2 
THREAD-3::::3 
THREAD-1::::1 
THREAD-2::::2 
THREAD-3::::3 
... 
*/