线程八大核心【一】

1.创建线程的方式

前面我看过很多的博客,部分有说创建线程有多种方式,但JDK1.8源码Thread中有这么一段话.

There are two ways to create a new thread of execution.One is to declare a class to be a subclass of Thread,The other way to create a thread is to declare a class that implements the Runnable interface.

官方给出的说明是本质上只有两种方式:1.继承Thread类,2.实现Runnable接口。但还有很多外在的表现形式,例如lambda表达式,线程池等。

public class NewThread {
    /*扩展自Thread类*/
    private static class UseThread extends Thread{
        @Override
        public void run() {
            super.run();
            // do my work;
            System.out.println("I am extendec Thread");
        }
    }
    /*实现Runnable接口*/
    private static class UseRunnable implements Runnable{

        @Override
        public void run() {
            // do my work;
            System.out.println("I am implements Runnable");
        }
    }
    
    public static void main(String[] args) 
            throws InterruptedException, ExecutionException {
        UseThread useThread = new UseThread();
        useThread.start();
        UseRunnable useRunnable = new UseRunnable();
        new Thread(useRunnable).start();
    }

2.停止线程的正确姿势

2.1 继承Thread,执行方法体中没有InterruptException

直接上代码:

public class EndThread {
    private static class UseThread extends Thread{
        public UseThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName+" interrrupt flag ="+isInterrupted());
            while(!isInterrupted()){
                //while(!Thread.interrupted()){
                System.out.println(threadName+" is running");
                System.out.println(threadName+"inner interrrupt flag ="
                        +isInterrupted());
            }
            System.out.println(threadName+" interrrupt flag ="+isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread endThread = new UseThread("endThread");
        endThread.start();
        Thread.sleep(20);
        endThread.interrupt();//中断线程,其实设置线程的标识位true
    }
}

2.1.1 说明:

stop()、suspend()也能停止线程,那么为什么要将其标注为Deprecated(过时)的方法呢?原因就是这种方式是抢占式的,比如:有一个任务在写文件,文件的总大小为10M,现在写了5M,突然收到stop()的中断,导致线程突然停止,那么这样就破坏了文件的完整性。使用interrupt()方法的好处就是,调用该方法时会给线程的中断标志位设置为true,并把中断线程的决定权交给线程自己,这种方式就是协作式,等任务处理完再结束。

2.1.2 isInterrupt()与Thread.interrupt()静态方法的区别

相同点:调用interrupt()方法时,两者都能获取线程的中断标志位状态为true
不同点:Thread.interrupt()在判断完之后会将中断标志位重置为false

2.2 实现Runnable,执行方法体中没有InterruptException

public class EndRunnable {
    private static class UseRunnable implements Runnable{
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + " I am implements Runnable.");
            }
            System.out.println(Thread.currentThread().getName()
                    +" interrupt flag is "+Thread.currentThread().isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        UseRunnable useRunnable = new UseRunnable();
        Thread endThread = new Thread(useRunnable,"endThread");
        endThread.start();
        Thread.sleep(20);
        endThread.interrupt();
    }
}

2.3 执行方法体中有InterruptException

当线程的执行体中出现了sleep、await、join等会抛出interruptException异常的方法时,需要特别注意,就例如下面的程序。线程调用interrupt方法时,线程的执行体会捕获到interruptException异常,进入到catch中,这时会将线程的中断标志位重置为false。这样做的意义在于:如果不重置为false的话,线程收到中断请求立马就结束了那么与stop方法没有区别了,如果重置为false,程序可以在catch中做未完成的工作,如释放资源等,做完这些收尾的工作之后再手动的调用一次interrupt()方法,结束线程。

/**
 *类说明:阻塞方法中抛出InterruptedException异常后,如果需要继续中断,需要手动再中断一次
 */
public class HasInterrputException {
    private static class UseThread extends Thread{
        public UseThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            while(!isInterrupted()) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()
                            +" in InterruptedException interrupt flag is "
                            +isInterrupted());
                    //资源释放
                    //interrupt();
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + " I am extends Thread.");
            }
            System.out.println(Thread.currentThread().getName()
                    +" interrupt flag is "+isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread endThread = new UseThread("HasInterrputEx");
        endThread.start();
        Thread.sleep(500);
        endThread.interrupt();    
    }
}

2.4 错误的结束线程方式

设置标志标志位,通过判断标志位来中断线程,这种方式的不合理因素在于,如果线程执行体中的方法长时间被阻塞,导致循环阻塞,中断标志位失效。

/**
 *类说明:设置标志位中断线程
 */
public class HasInterrputException {
    
    private static class UseThread extends Thread{
        private volatile boolean flag = false;

        public UseThread(String name) {
            super(name);
        }
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
        @Override
        public void run() {
            while(!flag) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()
                            +" in InterruptedException interrupt flag is "
                            +isInterrupted());
                    //资源释放
                    //interrupt();
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + " I am extends Thread.");
            }
            System.out.println(Thread.currentThread().getName()
                    +" interrupt flag is "+isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread endThread = new UseThread("HasInterrputEx");
        endThread.start();
        Thread.sleep(500);
        ((UseThread) endThread).setFlag(true);
    }
}

3.线程的状态转化

jdk源码对Thread类定义了6个状态,分别为:

 public enum State {
        
        NEW,

        RUNNABLE,
        
        BLOCKED,

        WAITING,

        TIMED_WAITING,

        TERMINATED;
    }

线程的6个状态.png

4.Thread类的主要方法

阅读 176

推荐阅读