Java thread state correct posture and close the thread

1, and the switching state of the thread

  Java threads in six states have, within the enumeration class using threads Thread to realize, as I have for each state a certain amount of interpretation.

  public  enum State {
         / ** represents a thread not enabled (ie start method is not called) * / 
        NEW, 

        / ** 
         * JVM threads are executed in this state, but in this state may not execute in the JVM , 
         * that is, only the state are eligible to obtain a JVM scheduled execution time slice. 
         * / 
        RUNNABLE, 

        / ** 
         * threads waiting to acquire a lock to enter the blocked state resources, 
         * in this state, which has been monitoring the dynamic lock, ready to seize the lock 
         * If you get a lock resources, re-enter the RUNNABLE state 
         * / 
        BLOCKED, 

        / ** 
         * when calling Object.wait, Thread.join or class of park LockSupport method, the thread enters this state, 
         * the state if no other active threads wake up, no waiting period. 
         * Wake-up method includes: Object.notify (random wake a), Object.notifyAll (wake up all the threads), 
         * thread to be awakened to re-enter RUNNABLE state 
         * / 
        the WAITING,

        / ** 
         * WAITING same state, but the difference is the method invoked added time constraints, 
         * such as: Object.wait (10), Thread.sleep ( 10), Thread.join (10), LockSupport.parkNanos ( 10), LockSupport.parkUntil (10) of these methods 
         * wake of two ways: 
         * 1, time expired. 
         * 2, another thread calls notify or notifyAll 
         * RUNNABLE into the same state after wake 
         * / 
        TIMED_WAITING, 

        / ** end thread (natural death or been terminated) * / 
        TERMINATED; 
    }

   And except NEW TERMINATED, other states are interchangeable, the conversion process as shown in FIG.

 

  Here to talk about the particular RUNNABLE state, the thread is not necessarily in the execution of the program in this state, only the JVM thread scheduling time slice to get executed, and only the thread of this state to be able to get time slice, in other words, the JVM and obtains the scheduling time slice belongs only RUNNABLE claimed in state of the thread . For ease of understanding, RUNNABLE can be divided into Runnable and Running two states (of course, you can also replace the other, and here I only understand their own good), then the above thread conversion chart turned into this (refer to "Java Concurrency Art thread state diagram programming "in):

 

   Examples of state transitions on the thread can be produced by the following code better understanding

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        // 1.NEW状态
        Thread thread = new Thread(() -> {
            // 3.进行test对象锁的争夺,若抢到锁则继续执行,否则进入BLOCKED状态监控该锁,重新获得后进入RUNNABLE 
            synchronized (test) {
                try {
                    // 4.进入TIMED_WAITING状态,100ms后重新进入RUNNABLE状态争夺时间片 
                    Thread.sleep(100);
                    // 5.重新获得时间片之后,进入WAITING状态 
                    test.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 6.正常run()方法执行完毕后线程结束,进入TERMINATED 
        });
        // 2.调用start()方法,线程进入RUNNABLE状态
        thread.start();
    }
}

注:代码执行的顺序为注释的序号

 2、正确的结束一个线程

  在上面的例子中我们看到线程的run方法正常执行完毕之后线程就正常死亡进入TERMINATED状态了,那么如果我们有中途停止线程的需求,我们应该如何正确的结束一个线程呢?

  1. 使用interrupt()方法:在线程内部,其定义了一个变量来标识当前线程是否处于被打断状态,调用interrupt()方法则使这个状态变为true。我们采用这个方法加异常处理的方式来结束一个线程。
      public static void main(String[] args) {
            Thread thread = new Thread(() -> {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // 这里的return是必须的,原因后面说明
                    return;
                }
                System.err.println("thread interrupt test...");
            });
            thread.start();
            thread.interrupt();
            System.out.println("main thread end...");
        }

    // 结果图:异常后面的语句不会打印


      这里关于线程中的打断标识变量(之后以interrupt称)需要说明的是,在特定的情况下其状态会被重置。
       1、线程内部在catch了异常了之后interrupt的状态会被重置为false。
    2、线程调用了Thread.interrupted()方法之后,interrupt的状态会被重置为false。如果需要判断线程是否中断的话可以使用对象方法isInterrupted(),此方法不会重置。
    所以在刚才的代码中需要加入return来结束线程,否则的话线程还是会继续往下执行,如下图


    使用isInterrupted()实现:
    public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
    int k = 0;
    while (k++ < 10) {
    System.out.println("do something..." + k);
    }
    }
    System.err.println("thread end...");
    });
    thread.start();
    Thread.sleep(1);
    // 主线程流程执行完了,需要停止线程
    thread.interrupt();
    }

      

  2. 使用标识位来实现:定义一个变量标识线程是否终止,若终止了则退出run方法。跟上面isInterrupted()的实现一样,不过换成了volatile变量而已。
    public class Test {
    
        public static volatile boolean interrupted = false;
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(() -> {
                while (!interrupted) {
                    int k = 0;
                    while (k++ < 10) {
                        if (interrupted) {
                            System.err.println("thread invoke end....");
                            return;
                        }
                        System.out.println("do something..." + k);
                    }
                }
            System.err.println("thread end...");
            });
            thread.start();
            Thread.sleep(1);
            // 主线程流程执行完了,需要停止线程
            interrupted = true;
        }
    }
    // 结果图

     

 stop()方法——不正确的线程中断方法

    在线程提供的方法中还有一个方法可以强制关闭线程——stop()。这个方法可以说是相当的霸道,给人一种“我不管,我就是要你现在立刻死亡(指线程)”的感觉,并且其还会释放线程所有的锁资源,这样可能会导致出现数据不一致从而出现线程不安全的情况,如下面例子。

public class Test {

        public static volatile boolean flag = false;
        public int state = 0;

        public static void main(String[] args) throws InterruptedException {
            Test test = new Test();
            Thread thread = new Thread(() -> {
                synchronized (test) {
                    try {
                        test.state = 1;
                        Thread.sleep(100);
                        if (flag) {
                            test.state = 2;
                        }
                        System.err.println("thread execute finished...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
            Thread.sleep(1);
            thread.stop();
            flag = true;
            System.out.println("state状态:" + test.state);
        }
}
// 在这段代码中,进入线程时默认将state赋为1,接着过一段时间后如果触发了特定条件则把state赋为2,但是在特定条件触发之前,线程就被终止掉了,这个特定条件虽然符合但却没办法执行,从而导致数据的不一致。
// 结果图
  

  所以,我们应该采用上面两种正确的方式而不是stop()来中止线程。此外,stop()方法若在线程start()之前执行,那么在线程启动的时候就会立即死亡。

 

 

若有不对之处,望各位不吝指教(反正免费,对吧)。

Guess you like

Origin www.cnblogs.com/zhangweicheng/p/11695849.html