2016-04-26 12 views
0

Es ist eine Multithreading-Übung, in der ich einen Monitor verwenden, um Threads zu synchronisieren. Ich habe kein Problem mit Monitor oder Synchronisation, es gibt kein Deadlock. Ich möchte hauptsächlich einige Threads erstellen. Der folgende Code erzeugt Threads, fügt sie zu einer ArrayList hinzu und startet sie. Erzeugt verschiedene Threads mit einem Switch-Case. Da jeder Thread zu ArrayList hinzugefügt und gestartet werden soll, setze ich diese beiden Zeilen am Ende des Switch-Falls, um nicht in jedem Fall den gleichen Code zu schreiben. Aber auf diese Weise wird eine IllegalThreadStateException gestartet.Wie erstellt man Threads zu vermeiden IllegalThreadStateException

Um meinen Code arbeiten zu lassen, kann ich verschiedene Ansätze anwenden, aber ich habe einige Zweifel für alle von ihnen. Welcher wäre der am besten geeignete Weg?

Erstellen Sie eine Funktion, die eine neue myThread-Instanz erstellt, fügen Sie sie der ArrayList hinzu und starten Sie sie. Aber da ich es von main aus aufrufen muss, oder es sollte statisch sein (wie ich weiß, ist das Erstellen einer statischen Funktion ohne einen guten Grund nicht eine gute Übung) oder ich sollte es wie new myClass().someMethod() nennen, aber da ich viele neue Threads erstellen muss , es würde viele Instanzen von myClass erstellen, scheint nicht gut zu sein.

public class myClass { 

    public static void main(String[] args) { 

     int scount=10, tcount=5, pcount=5; 
     final int SIZE = 20; 


     ArrayList<User> users = new ArrayList<User>(); 
     myMonitor monitor = new myMonitor(SIZE); 
     User u = null; 
     int s = 0, t = 0, p = 0; //counters 

     //GENERATED CASUALLY DIFFERENT TYPE OF THREADS 
     while(s < scount || t < tcount || p < pcount){ 

      int type = (int)(Math.random() * 3); 

      switch(type){ 
      case 0: 
       if(p < pcount){ 
        u = new User(monitor, p, "USER_TYPE_1"); 
        p++;     
       } 
       break; 
      case 1: 
       if(t < tcount){ 
        u = new User(monitor, p, "USER_TYPE_2"); 
        t++; 
       } 
       break; 
      case 2: 
       if(s < scount){ 
        u = new User(monitor, p, "USER_TYPE_2"); 
        s++; 
       } 
       break; 
      } 
      users.add(u); 
      u.start(); 
     } 

    } 

} 

public class User extends Thread{ 
    myMonitor monitor; 
    final private int number; 
    final private String type; 
    final private int k; 
    final private int MIN = 1; 
    final private int MAX = 5; 


public User(myMonitor monitor, int number, String type) { 
    this.monitor = monitor; 
    this.number = number; 
    this.type = type; 
    this.k = (int)(Math.random() * ((MAX - MIN) + 1)) + MIN; 
} 

public int getNumber() { 
    return number; 
} 

public String getType() { 
    return type; 
} 

@Override 
public void run(){ 

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

     switch(this.type){ 
      case "TYPE1": 
       monitor.startType1(); 
       break; 
      case "TYPE2": 
       monitor.startType2(i); 
       break; 
      case "TYPE3": 
       monitor.startType3(); 
       break; 
     } 

     try{ 

      Long duration = (long) Math.ceil(Math.random() * 1000); 
      Thread.sleep(duration); 
      System.out.printf("%s-%d used system for the %d.time. Took %d ms\n", 
        this.type, this.number, i+1, duration); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

     switch(this.type){ 
      case "TYPE1": 
       monitor.endType1(); 
       break; 
      case "TYPE2": 
       monitor.endType2(i); 
       break; 
      case "TYPE3": 
       monitor.endType3(); 
       break; 
     } 

     try{ 
      Long duration = (long) Math.ceil(Math.random() * 1000); 
      Thread.sleep(duration); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

    } 
    System.out.printf("%s-%d finished\n", this.type, this.number); 
} 

}

+0

Was Sie versuchen zu tun? Der Code macht absolut keinen Sinn. Sie haben nicht lange mit Java programmiert, oder? – Kayaman

+0

Es ist nur ein Multithreading-Beispiel, da ich kein Problem mit der Synchronisation usw. habe. Ich habe den Code nicht hinzugefügt. Aber jetzt bearbeitet, ich hoffe es ist klarer. Aber es hängt nicht davon ab, wie lange ich mit Java programmieren kann ... – user3717434

Antwort

0

Läßt ein Gedankenexperiment durchführen, Math.random * 3 immer wieder 0 - dies möglich ist, weil es offensichtlich random ist (nur unwahrscheinlich).

Iteration 1

int s == t == p == 0 

Wir betreten den ersten Fall als type == 0. Wir erzeugen ein neues "P" Thread und add es zu den List und start() es.

p++ 

Iteration 2

int s == t == 0; p == 1 

Wir betreten den ersten Fall als type == 0. Wir erzeugen ein neues "P" Thread und add es zu den List und start() es.

p++ 

...

Iteration 5

int s == t == 0; p == 4 

Wir betreten den ersten Fall als type == 0.Wir erzeugen ein neues "P" Thread und add es zu den List und start() es.

p++ 

Iteration 6

int s == t == 0; p == 5 

Wir betreten den ersten Fall als type == 0. Wir tun nichts als p> = pcount. Unsere thrd verweist immer noch auf die Thread, die wir in Iteration 5 erstellt haben.

Wir fügen den gleichen Thread zum List und start() es. Jetzt

IllegalThreadStateException 

, offensichtlich Math.random * 3 unterschiedliche Werte zurückgeben, aber es wird Duplikate zurückgeben (und Ihr Code um, dass entworfen) - so dass Sie wird diese Situation bekommen.

Wie kann ich es vermeiden? Nun, Sie nicht wirklich wollen Zufallszahlen erzeugen:

final List<Integer> desiredValues = new ArrayList<>(Arrays.asList(0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2)); 
Collections.shuffle(desiredValues) 
for(final Integer value : desiredValues) { 
    //case switch 
} 
+0

Sie haben Recht, ich habe diese Situation nicht erkannt. Collection.shuffle() ist ein guter Ratschlag. Vielen Dank! – user3717434

+0

meine IDE sagt, dass Liste nicht generisch ist, kann nicht mit Argumenten ... – user3717434

+0

Wrong 'List' parametrisiert werden. Überprüfen Sie Ihre Importe. –

0

Du nennst thrd.start(); auch wenn ein neuer Thread nicht erstellt wurde. Da Sie die Variable außerhalb der Schleife deklariert haben, verweist sie immer noch auf den zuvor gestarteten Thread. Ein zweimaliger Aufruf von start() in einem Thread führt zu einer Ausnahme.

Verschieben Sie myThread thrd = null; innerhalb der while Schleife, und rufen Sie nur start();, wenn es nicht null ist.

+0

Das ist nicht wirklich erforderlich - siehe meine Antwort. Das OP möchte eine feste Menge von Werten in zufälliger Reihenfolge erzeugen - keine zufälligen Werte. –

+0

Nun offensichtlich nicht. Ich war am wenigsten Änderungen am Original. – Kayaman

Verwandte Themen