美文网首页Java 杂谈
《Java多线程编程核心技术》(一)

《Java多线程编程核心技术》(一)

作者: 小编 | 来源:发表于2018-06-07 16:49 被阅读33次

    概要:
    学习使用Thread.currentThread()
    了解中断线程的方法
    了解sleep方法抛出异常

    Thread.currentThread()

    Thread.currentThread()方法可返回代码正在被哪个线程调用的信息。

    public class Counter extends Thread {
    
        //构造方法在主线程中被执行
        public Counter() {
            print("constructor begin");
    
            print("Thread.currentThread().getName()------"+Thread.currentThread().getName());//main
            print("this.getName()-----------"+this.getName());//Thread-0
    
            print("constructor end");
        }
    
        @Override
        public void run() {
            //在子线程中被执行
            print("run begin");
    
            print("Thread.currentThread().getName()--------"+Thread.currentThread().getName());
            print("this.getName()--------"+this.getName());
    
            print("run end");
        }
    
    
        private void print(String msg){
            System.out.println(msg);
        }
    }
    
    public class Run {
    
        public static void main(String[] args){
            Counter counter = new Counter();
    
            Thread t = new Thread(counter);
            t.setName("new");
            t.start();
        }
    }
    
    /** 执行结果如下:
    constructor begin
    Thread.currentThread().getName()------main
    this.getName()-----------Thread-0
    constructor end
    run begin
    Thread.currentThread().getName()--------new
    this.getName()--------Thread-0
    run end
    */
    

    如上,Counter构造方法是在main线程中执行。run()方法是在new线程中执行的。

    this.getName()this指代的是Counter实例,Counter继承Thread,在初始化会设置名称为Thread-0

    第二个线程t初始化,名称默认为Thread-1,后续重新赋值为new

    停止线程

    有三种方法可以使终止线程。
    1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
    2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
    3. 使用interrupt方法中断线程。

    interrupt()方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程
    换句话说,调用该方法的线程会被设置一个“中断”状态,用于判断的中断状态的方法如果返回true说明中断状态被设置了。

    如何判断线程的状态是不是停止的?Thread.java类里提供了两种方法:
    1)this.interrupted(): 测试当前线程是否已经是中断状态,执行后具有将状态标志置为false的功能。如果这个方法被连续调用两次,第二次调用将返回false。
    2)this.isInterrupted(): 测试线程Thread对象是否已经是中断状态,但不清除状态标识。

    第一种方法,判断当前线程的状态;第二个方法,判断调用者的中断状态。

    源码:

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    
    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    private native boolean isInterrupted(boolean ClearInterrupted);
    

    从源码中可以看出,最终调用的是isInterrupted(boolean ClearInterrupted)方法,参数ClearInterrupted可以控制中断状态清除。

    验证1:
    如下代码虽然调用了interrupted()方法,但是从运行结果来看,线程并未停止。

    
    class MyThread extends Thread{
        @Override
        public void run() {
            for(int i =0;i<1000;i++){
                System.out.println("number"+i);
            }
        }
    }
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyThread t = new MyThread();
            t.start();
            //主线程运行10毫秒之后,中断子线程t。但是并没有效果。仅仅是打了一个标记
            Thread.sleep(10);
            t.interrupt();
        }
    }
    

    验证2:
    从运行结果可以看出,t.interrupted()返回的是当前线程的状态,即main线程,main从未调用过interrupt()方法,未被标记过状态,因此返回的结果都是false

    t.isInterrupted()返回的是t线程的中断状态。主线程运行10毫秒之后,调用中断方法,此时返回状态为true,表示t.interrupt()方法生效了。

    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyThread t = new MyThread();
            t.start();  
            //主线程运行10毫秒之后,中断子线程t。     
            Thread.sleep(10);
            t.interrupt();
            System.out.println("当前线程0:"+t.interrupted());
            System.out.println("停止线程1:"+t.isInterrupted());
            Thread.sleep(1000);
            System.out.println("当前线程0:"+t.interrupted());
            System.out.println("停止线程1:"+t.isInterrupted());
        }
    }
    
    /**
    当前线程0:false
    停止线程1:true
    当前线程0:false
    停止线程1:false
    */
    

    验证3
    连续两次调用interrupted()方法,第二次调用将返回false

    public class Run {
        public static void main(String[] args) throws InterruptedException {
            Thread.currentThread().interrupt();
            System.out.println("停止线程:"+Thread.currentThread().interrupted());
            System.out.println("停止线程:"+Thread.currentThread().interrupted());
        }
    }
    /**
    停止线程:true
    停止线程:false
    */
    

    应用
    interrupt()方法和isInterrupted()方法结合使用,来停止线程。

    1.使用break停止线程

    public class Counter0 extends Thread {
        @Override
        public void run() {
            super.run();
            for (int i = 0; i < 100000; i++) {
                if(this.isInterrupted()){
                    System.out.println("已经标记了停止状态,我要退出");
                    break;
                }
                System.out.println("number"+i);
            }
            System.out.println("退出for循环,后面依然执行");
    }
    public class Run {
    
        public static void main(String[] args){
            try {
                Counter0 counter0 = new Counter0();
                counter0.start();
                Thread.sleep(10);
                counter0.interrupt();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /**
    number776
    number777
    number778
    number779
    number780
    已经标记了停止状态,我要退出
    退出for循环,后面依然执行
    */
    

    使用break的方式并未完全退出子线程,for循环之外的代码仍然在执行

    改进:

    2.使用抛异常的方式,停止线程执行

    public class Counter0 extends Thread {
        @Override
        public void run() {
            try{
                for (int i = 0; i < 100000; i++) {
                    if(this.isInterrupted()){
                        System.out.println("已经标记了停止状态,我要退出");
                        throw new InterruptedException();
                    }
                    System.out.println("number"+i);
                }
    
                System.out.println("退出for循环,后面依然执行");
            }catch (InterruptedException e){
                System.out.println("捕获异常");
            }
        }
    }
    /**
    number983
    number984
    number985
    已经标记了停止状态,我要退出
    捕获异常
    */
    

    在沉睡中停止线程

    public class Thread implements Runnable{
        /**
         * Causes the currently executing thread to sleep (temporarily cease
         * execution) for the specified number of milliseconds, subject to
         * the precision and accuracy of system timers and schedulers. The thread
         * does not lose ownership of any monitors.
         *
         * @param  millis
         *         the length of time to sleep in milliseconds
         *
         * @throws  IllegalArgumentException
         *          if the value of {@code millis} is negative
         *
         * @throws  InterruptedException
         *          if any thread has interrupted the current thread. The
         *          <i>interrupted status</i> of the current thread is
         *          cleared when this exception is thrown.
         */
        public static native void sleep(long millis) throws InterruptedException;
    }
    

    InterruptedException当前线程睡眠中,如果有任何线程中断了当前线程,抛出异常。当抛出异常时,当前线程的中断状态被清除,值为false

    举个栗子:

    public class Counter0 extends Thread {
    
        @Override
        public void run() {
            super.run();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                System.out.println("状态标记:"+this.isInterrupted());
                e.printStackTrace();
            }
        }
    }
    public class Run {
        public static void main(String[] args){
            try {
                Counter0 counter0 = new Counter0();
                counter0.start();
                Thread.sleep(10);
                counter0.interrupt();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /**
    状态标记:false
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at com.yolo.thread.Counter0.run(Counter0.java:37)
    */
    

    相关文章

      网友评论

        本文标题:《Java多线程编程核心技术》(一)

        本文链接:https://www.haomeiwen.com/subject/fgggsftx.html