zoukankan      html  css  js  c++  java
  • 同一个线程多次调用start()会出现的问题

    结果:

      线程首先会运行一次,然后抛出java.lang.IllegalThreadStateException异常。

      

    根据控制台的异常信息,定位到Thread.java的第708行,也就start()方法内部,打个断点调试:

      

     调试发现,第一个次运行start()方法时,threadStatus是0,此时if条件不满足,继续执行,会将当前线程添加到线程组中去执行。

    第二次运行start()方法时,threadStatus变成了2,if条件满足,于是抛出了java.lang.IllegalThreadStateException异常。

    start()方法的源码:

    /**
         * Causes this thread to begin execution; the Java Virtual Machine
         * calls the <code>run</code> method of this thread.
          让这个线程开始执行。JVM会调用这个线程的run()方法。
         * <p>
         * The result is that two threads are running concurrently: the
         * current thread (which returns from the call to the
         * <code>start</code> method) and the other thread (which executes its
         * <code>run</code> method).
         * <p>
         * It is never legal to start a thread more than once.一个线程多次调用start()方法是非法的。
         * In particular, a thread may not be restarted once it has completed
         * execution.
         *特别说明:一个线程执行完后,不太可能重新运行。
         * @exception  IllegalThreadStateException  if the thread was already
         *               started.
                  如果该线程已经启动,则再次调用start()方法,就会抛出IllegalThreadStateException异常。
         * @see        #run()
         * @see        #stop()
         */
        public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0)//新的线程threadState值是0
                throw new IllegalThreadStateException();
    
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            group.add(this);//通知线程组该线程将要开始运行,这样该线程就会被添加到线程列表中,此时列表的unstarted数将会减少。
    
            boolean started = false;
            try {
                start0();//调用原生方法态方法启动线程
                started = true;//已经运行的标记设置为true
            } finally {
                try {
                    if (!started) {//若开始运行标记未设置成功,则通知线程组该线程尝试运行失败
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }

    group.add(this)  ---线程组添加线程源码分析

    /**
         * Adds the specified thread to this thread group.
         * 添加特定的线程到该线程组
         * <p> Note: This method is called from both library code
         * and the Virtual Machine. It is called from VM to add
         * certain system threads to the system thread group.
         *
         * @param  t
         *         the Thread to be added
         *
         * @throws  IllegalThreadStateException
         *          if the Thread group has been destroyed
         */
        void add(Thread t) {
            synchronized (this) {//线程同步
                if (destroyed) {//如果线程组的销毁标记(destroyed)是true,则抛出IllegalThreadStateException
                    throw new IllegalThreadStateException();
                }
                if (threads == null) {//如果线程数组为空,则初始为4个新的线程
                    threads = new Thread[4];
                } else if (nthreads == threads.length) {//如果当前线程组已满,则扩容至原来的2倍
                    threads = Arrays.copyOf(threads, nthreads * 2);
                }
                threads[nthreads] = t;//将当前线程放入线程数组的末尾
    
                // This is done last so it doesn't matter in case the
                // thread is killed
                nthreads++;//线程数组元素个数+1
    
                // The thread is now a fully fledged member of the group, even
                // though it may, or may not, have been started yet. It will prevent
                // the group from being destroyed so the unstarted Threads count is
                // decremented.
                nUnstartedThreads--;//未启动线程数-1
            }
        }

    threadStartFailed()源码分析:

    /**
         * Notifies the group that the thread {@code t} has failed
         * an attempt to start.
         * 通知线程组该线程尝试运行失败
         * <p> The state of this thread group is rolled back as if the
         * attempt to start the thread has never occurred. The thread is again
         * considered an unstarted member of the thread group, and a subsequent
         * attempt to start the thread is permitted.
         *
         * @param  t
         *         the Thread whose start method was invoked
         */
        void threadStartFailed(Thread t) {
            synchronized(this) {//同步
                remove(t);//从线程组中移除该线程
                nUnstartedThreads++;//未启动线程数+1
            }
        }

    结论:

    同一个线程只能调用start()方法一次,多次调用会抛出java.lang.IllegalThreadStateException。启动一个线程,需要调用start()方法而不是run()方法。此时,当前线程会被添加到线程组中,进入就绪状态,等待线程调度器的调用,若获取到了资源,则能进入运行状态,run()方法只是线程体,即线程执行的内容,若没调用start()方法,run()方法只是一个普通的方法。

  • 相关阅读:
    排序算法合集(冒泡,选择,插入,堆排,快排)
    codeforces 632+ E. Thief in a Shop
    nyoj-一笔画问题-欧拉图+联通判定
    hdu-1179-二分图最大匹配
    hdu-2063-二分图最大匹配
    (转)二分图的最大匹配、完美匹配和匈牙利算法
    hdu-2444-二分图判定+最大分配
    C
    E
    C
  • 原文地址:https://www.cnblogs.com/yufeng218/p/9940562.html
Copyright © 2011-2022 走看看