为什么再次调用Thread.start时会发生IllegalThreadStateException

时间:2011-11-09 22:59:04

标签: java multithreading

public class SieveGenerator{

static int N = 50;
public static void main(String args[]){

    int cores = Runtime.getRuntime().availableProcessors();

    int f[] = new int[N];

    //fill array with 0,1,2...f.length
    for(int j=0;j<f.length;j++){
        f[j]=j;
    }

    f[0]=0;f[1]=0;//eliminate these cases

    int p=2;

    removeNonPrime []t = new removeNonPrime[cores];

    for(int i = 0; i < cores; i++){
        t[i] = new removeNonPrime(f,p);
    }

    while(p <= (int)(Math.sqrt(N))){
        t[p%cores].start();//problem here because you cannot start a thread which has already started(IllegalThreadStateException)
        try{
            t[p%cores].join();
        }catch(Exception e){}
        //get the next prime
        p++;
        while(p<=(int)(Math.sqrt(N))&&f[p]==0)p++;
    }


    //count primes
    int total = 0;
    System.out.println();

    for(int j=0; j<f.length;j++){
        if(f[j]!=0){
            total++;
        }
    }
    System.out.printf("Number of primes up to %d = %d",f.length,total);
}
}


class removeNonPrime extends Thread{
int k;
int arr[];

public removeNonPrime(int arr[], int k){
    this.arr = arr;
    this.k = k;
}

public void run(){
    int j = k*k;
    while(j<arr.length){
        if(arr[j]%k == 0)arr[j]=0;
        j=j+arr[k];

    }
}
}

嗨我在运行代码时遇到IllegalThreadStateException并且我认为这是因为我正在尝试启动一个已经启动的线程。那我怎么能杀了 或者每次都停止线程,以解决这个问题?

7 个答案:

答案 0 :(得分:9)

  

我怎样才能每次杀死或停止线程,以解决这个问题?

答案是,你做不到。启动后,Thread可能无法重新启动。 Thread new清楚地记录了这一点。相反,每次你在循环中出现时,你真正想做的是RemoveNonPrime p的实例。

您的代码中还有其他一些问题。 首先,您需要在再次使用之前增加for(int i = 0; i < cores; i++){ t[i] = new removeNonPrime(f,p); //<--- BUG, always using p=2 means only multiples of 2 are cleared }

while(p <= (int)(Math.sqrt(N))){
    t[p%cores].start();//
    try{
        t[p%cores].join(); //<--- BUG, only the thread which was just started can be running now
    }catch(Exception e){}
    //get the next prime
    p++;
    while(p<=(int)(Math.sqrt(N))&&f[p]==0)p++;
}

其次,您可能是多线程的,但您不是并发的。您拥有的代码基本上只允许一次运行一个线程:

/* A queue to trick the executor into blocking until a Thread is available when offer is called */
public class SpecialSyncQueue<E> extends SynchronousQueue<E> {
    @Override
    public boolean offer(E e) {
        try {
            put(e);
            return true;
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
}

ExecutorService executor = new ThreadPoolExecutor(cores, cores, new SpecialSyncQueue(), ...);
void pruneNonPrimes() {
    //...
    while(p <= (int)(Math.sqrt(N))) {
        executor.execute(new RemoveNonPrime(f, p));
        //get the next prime
        p++;
        while(p<=(int)(Math.sqrt(N))&&f[p]==0)p++;
    }


    //count primes
    int total = 0;
    System.out.println();

    for(int j=0; j<f.length;j++){
        if(f[j]!=0){
            total++;
        }
    }
    System.out.printf("Number of primes up to %d = %d",f.length,total);
}



class RemoveNonPrime extends Runnable {
    int k;
    int arr[];

    public RemoveNonPrime(int arr[], int k){
        this.arr = arr;
        this.k = k;
    }

    public void run(){
        int j = k*k;
        while(j<arr.length){
            if(arr[j]%k == 0)arr[j]=0;
            j+=k;
        }
    }
}

只是我的0.02美元,但你想要做的可能会工作,但是选择下一个最小素数的逻辑并不总是选择素数,例如,如果其他一个线程没有处理该数组的那部分爱好。

这是一种使用ExecutorService的方法,你需要填写一些空白(...):

{{1}}

答案 1 :(得分:1)

您可以实现Runnable并使用新的Thread($ Runnable here).start()或使用ExecutorService来重用线程。

答案 2 :(得分:1)

* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException  if the thread was already started
*/
public synchronized void start() {

在Android中,文档仍然提到我们将获得IllegalThreadStateException if the thread was already started 但是对于某些设备,它不会抛出此异常(在Kyocera 7.0上测试)。在像三星,HTC这样的流行设备中,它通常抛出异常

我在这里回答是因为Android问题标记为与此问题重复。

答案 3 :(得分:0)

ThreadPools可用于传递任务以设置线程数。启动时设置线程数。然后,您为池添加任务。并且在您可以阻止所有任务完成处理之后。 Here是一些示例代码。

答案 4 :(得分:0)

我完全不确定我理解这个问题。不推荐使用从其他线程执行的所有停止线程的方法;停止线程的方法是让它检查它和另一个线程可以访问的变量(可能是 volatile 变量),并让正在运行的线程偶尔检查它是否应该退出它的自己的。

我不知道为什么/是否要消除正在运行的线程并使用另一个线程,我无法看到不同线程如何帮助您更快地执行您的总体目标。但是我可能只是不理解数学。

答案 5 :(得分:0)

Thread.isAlive()方法可以告诉您线程是否已经启动。只需在你想要开始你的线程的地方这样做:

   if(!t[p%cores].isAlive()){
       t[p%cores].start();
   }

答案 6 :(得分:0)

为什么当Thread.start为IllegalThreadStateException发生 再次打电话

因为JDK / JVM实现者以这种方式编码Thread.start()方法。可以在线程完成执行后重新启动线程是一个合理的功能期望,这就是chrisbunney的答案(我在该答案中已经添加了注释)中所建议的内容,但是如果您查看Thread.start()实现中,第一行是

if (threadStatus != 0)
            throw new IllegalThreadStateException();

其中threadStatus == 0表示NEW状态,因此我的猜测是执行不会在执行完成后将线程重置为零并且线程处于TERMINATED状态(非零状态) )。因此,当您在相同的Thread上创建新的Runnable实例时,基本上可以将此状态重置为零。

此外,我注意到Phan Van Linh在某些操作系统上指出了不同的行为,在同一段中使用了 may 从不 >

启动一个线程永远不合法。特别是 完成执行后,线程可能无法重新启动。

我猜想他们在Javadoc上面想说的是,即使您在某些操作系统上没有获得IllegalThreadStateException,在Java / Thread类方式中也不合法,并且您可能会得到意想不到的行为。

著名的线程状态图描述了相同的情况-没有从死状态回到新状态。

enter image description here