这是一个多线程练习,我使用Monitor来同步线程。我没有监视器或同步问题,没有死锁。我想在main中创建一些线程。下面的代码生成线程,将它们添加到ArrayList并启动它们。使用switch-case生成不同的线程。由于每个线程都应该添加到ArrayList并启动,我将这两行放在switch-case的末尾,以便不在每种case-state中编写相同的代码。但是以这种方式它会启动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 :(得分:0)
即使未创建新主题,您也会调用thrd.start();
。因为你已经在循环之外声明了变量,所以它仍然会引用先前启动的线程。在线程上调用start()
两次将导致异常。
在myThread thrd = null;
循环内移动while
,如果它不为空,则只调用start();
。
答案 1 :(得分:0)
让我们进行思考实验,Math.random * 3
始终返回0
- 这是可能的,因为它显然是random(只是不太可能)。
迭代1
int s == t == p == 0
我们输入第一个案例,type == 0
。我们生成一个新的&#34; P&#34; Thread
和add
List
和start()
。
p++
迭代2
int s == t == 0; p == 1
我们输入第一个案例,type == 0
。我们生成一个新的&#34; P&#34; Thread
和add
List
和start()
。
p++
...
迭代5
int s == t == 0; p == 4
我们输入第一个案例,type == 0
。我们生成一个新的&#34; P&#34; Thread
和add
List
和start()
。
p++
迭代6
int s == t == 0; p == 5
我们输入第一个案例,type == 0
。 我们没有做任何事情,因为p&gt; = pcount 。我们的thrd
仍然指向我们在迭代5 中创建的Thread
。
我们将相同的Thread
添加到List
和start()
。
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
}