2016-04-26 78 views
0

这是一个多线程练习,我使用Monitor来同步线程。我没有监视器或同步问题,没有死锁。我想在主体中创建一些线程。下面的代码生成线程,将它们添加到ArrayList并启动它们。用开关盒生成不同的线程。由于每个线程都应该添加到ArrayList并启动,因此我将这两行放在switch-case的末尾,以便不在每个case-state中编写相同的代码。但是通过这种方式,它启动了一个IllegalThreadStateException。如何创建线程以避免IllegalThreadStateException

为了让我的代码有效,我可以应用不同的方法,但是我对它们都有些疑惑。哪一个是最合适的方法?

创建一个函数,它将创建一个新的myThread实例,将其添加到ArrayList并启动它。但因为我必须从main调用它,或者它应该是静态的(据我所知,创建一个静态函数没有一个很好的理由不是一个好习惯),或者我应该把它称为new myClass().someMethod(),但因为我必须创建许多新线程,它会创建myClass的很多实例,看起来不太好。

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

你到底想干什么?该代码绝对没有意义。你没有用Java编程很久,对吗? – Kayaman

+0

这只是一个多线程的例子,因为我没有同步等问题,我没有添加代码。但现在编辑它,我希望它更清楚。但它不取决于我用java编程多长时间... – user3717434

回答

0

让我们进行思考实验,Math.random * 3总是返回0 - 这是可能的,因为它明显是random(不太可能)。

迭代1

int s == t == p == 0 

我们进入第一种情况下,作为type == 0。我们生成一个新的“P”Threadadd它到Liststart()它。

p++ 

迭代2

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

我们进入第一种情况下,作为type == 0。我们生成一个新的“P”Threadadd它到Liststart()它。

p++ 

...

迭代5

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

我们进入第一种情况下,作为type == 0。我们生成一个新的“P”Threadadd它到Liststart()它。

p++ 

迭代6

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

我们进入第一种情况下,作为type == 0我们不做任何事,因为p> = pcount。我们的thrd仍然指向我们在Iteration 5中创建的Thread

我们添加相同ThreadListstart()它。

IllegalThreadStateException 

现在,很明显Math.random * 3将返回不同的值,但将返回重复(和你的代码是围绕设计) - 让你获得这种情况。

如何避免它?那么,你实际上并不希望生成随机数:

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

你说得对,我没有意识到这种情况。 Collection.shuffle()是一个很好的建议。谢谢! – user3717434

+0

我的IDE说List不是通用的,它不能用参数参数化... – user3717434

+0

错误的'List'。检查你的进口。 –

0

你打电话,即使没有创建一个新的线程thrd.start();。既然你已经在循环外声明了变量,它仍然会引用先前启动的线程。在线程上调用start()两次将导致异常。

while循环内移动myThread thrd = null;,并且如果它不为空,则只能调用start();

+0

这并不是真的需要 - 请参阅我的答案。 OP想要以随机顺序生成一组固定值 - 不是随机值。 –

+0

显然不是。我对原始数据进行了最少量的更改。 – Kayaman