Why does an IllegalThreadStateException occur when Thread.start is called again

后端 未结 7 1571
攒了一身酷
攒了一身酷 2020-12-01 16:15
public class SieveGenerator{

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

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

    int f[] =          


        
相关标签:
7条回答
  • 2020-12-01 16:40

    how could I kill or stop the thread each time, to get around this problem?

    The answer is, you can't. Once started, a Thread may not be restarted. This is clearly documented in the javadoc for Thread. Instead, what you really want to do is new an instance of RemoveNonPrime each time you come around in your loop.

    You have a few other problems in your code. First, you need to increment p before using it again:

    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
    }
    

    Second, you might be multithreaded, but you aren't concurrent. The code you have basically only allows one thread to run at a time:

    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++;
    }
    

    Just my $0.02, but what you are trying to do might work, but the logic for selecting the next smallest prime will not always pick a prime, for example if one of the other threads hasn't processed that part of the array yet.

    Here is an approach using an ExecutorService, there are some blanks (...) that you will have to fill in:

    /* 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 讨论(0)
  • 2020-12-01 16:41

    Why does an IllegalThreadStateException occur when Thread.start is called again

    Because JDK/JVM implementers coded Thread.start() method that way. Its a reasonable functional expectation to be able to restart a thread after a thread has completed its execution and that is what being suggested in chrisbunney's answer ( and I have put in a comment in that answer ) but if you look at Thread.start() implementation , the very first line is ,

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

    where threadStatus == 0 means NEW state so my guess is that implementation doesn't resets this state to zero after execution has completed & thread is left in TERMINATED state ( non - zero state ). So when you create a new Thread instance on same Runnable , you basically reset this state to zero.

    Also, I noticed the usage of word - may & never in same paragraph as different behavior is being pointed out by Phan Van Linh on some OSes,

    It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

    I guess what they are trying to say in above Javadoc that even if you don't get IllegalThreadStateException on certain OS, its not legal in Java/Thread class way & you might get unexpected behavior.

    The famous thread state diagrams depict the same scenario - no going back from dead state to new.

    0 讨论(0)
  • 2020-12-01 16:46

    You could implement Runnable instead and use new Thread( $Runnable here ).start() or use a ExecutorService to reuse threads.

    0 讨论(0)
  • 2020-12-01 16:50

    I am not at all sure I understand the question. All the methods for stopping threads that are executed from other threads are deprecated; the way to stop a thread is to have it check a variable that it and another thread can access (perhaps a volatile variable), and have the running thread check it occasionally to see if it should exit on its own.

    I cannot tell why/whether you want to eliminate the running thread and use another one, and I cannot see how the different threads are going to help execute your overall goal any faster. But it's possible I'm just not understanding the math.

    0 讨论(0)
  • 2020-12-01 16:52

    ThreadPools can be used for delivering tasks to set number of threads. When initiating you set the number of threads. Then you add tasks for the pool. And after you can block until all tasks have finished processing. Here is some sample code.

    0 讨论(0)
  • 2020-12-01 16:53
    * 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() {
    

    In Android, document still mention that we will get IllegalThreadStateException if the thread was already started.
    However for some device it will not throw this exception (tested on Kyocera 7.0). In some popular device like Samsung, HTC, it throw throw the exception normally

    I answer here because the Android question is mark as duplicated to this question.

    0 讨论(0)
提交回复
热议问题