再次调用thread.start时为什么会发生illegalthreadstateexception

mo49yndu  于 2021-06-29  发布在  Java
关注(0)|答案(7)|浏览(347)
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 当我运行代码时,我发现这是因为我试图启动一个已经启动的线程。所以,我怎么能每次都终止或停止线程,来绕过这个问题呢?

ipakzgxi

ipakzgxi1#

线程池可用于传递任务以设置线程数。启动时,设置线程数。然后为池添加任务。之后,您可以阻止,直到所有任务都已完成处理。下面是一些示例代码。

vuktfyat

vuktfyat2#

为什么再次调用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&never这个词在同一段落中的用法,因为不同的行为,
多次启动线程是不合法的。特别是,线程一旦完成执行,就不能重新启动。
我猜他们在上面的javadoc里想说什么,即使你不明白 IllegalThreadStateException 在某些操作系统上,以java/thread类的方式是不合法的&您可能会得到意外的行为。
著名的线程状态图描述了相同的场景-没有从死状态回到新状态。

enyaitl3

enyaitl33#


* 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上测试)。在一些流行的设备,如三星,宏达电,它抛出异常正常
我在这里回答是因为android问题被标记为这个问题的副本。

oxalkeyp

oxalkeyp4#

我一点也不确定我是否理解这个问题。所有停止从其他线程执行的线程的方法都已弃用;停止线程的方法是让它检查一个它和另一个线程可以访问的变量(可能是一个易失性变量),并让正在运行的线程偶尔检查它,看它是否应该自己退出。
我不知道为什么/是否要删除正在运行的线程并使用另一个线程,我也不知道不同的线程将如何帮助更快地执行您的总体目标。但有可能我只是不懂数学。

uxh89sit

uxh89sit5#

isalive()方法可以告诉您线程是否已经启动。只需在要开始线程的位置执行以下操作:

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

cs7cruho6#

我怎样才能每次都终止或停止线程,从而绕过这个问题?
答案是,你不能。一旦开始,一个 Thread 可能无法重新启动。javadoc中清楚地记录了这一点 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++;
}

只是我的$0.02,但是您正在尝试的操作可能会起作用,但是选择下一个最小素数的逻辑并不总是选择一个素数,例如,如果其他线程之一尚未处理数组的该部分。
下面是一个使用executorservice的方法,您需要填写一些空格(…):

/* 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;
        }
    }
}
8wtpewkr

8wtpewkr7#

您可以改为实现runnable并使用新线程($runnable here).start()或使用executorservice重用线程。

相关问题