Thread常用方法整理

  • Post author:
  • Post category:其他


文章目录


目录


前言


一、常见方法汇总


二、start方法


1.演示代码


2.说明




三、run()方法


1、演示代码


2、说明


四、join()、join(n)、join(n,m)方法


1、演示代码


2、说明


五、getId()方法


1、演示代码


2、说明


六、getName()及setName(String name)方法


1、演示代码


2、说明


七、getPriority()及setPriority(int newPriority)方法


1、演示代码


2、说明


八、yield() 方法


1、演示代码


2、说明


九、sleep(long millis)、sleep(long millis, int nanos) 方法


1、演示代码


2、说明


十、currentThread() 方法


1、演示代码


2、说明


十一、isAlive() 方法


1、演示代码


2、说明


十二、interrupt()、isInterrupted()、interrupted()方法


1、演示代码


2、说明


十三、getState() 方法


1、演示代码


2、说明


总结




前言

本文章记录Thread方法中的常用方法的用法




一、常见方法汇总

方法名 功能说明
start() 启动一个新线程,在新的线程运行run方法中的代码 start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException
run() 新线程启动后会调用的方法 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作。但可以创建 Thread 的子类对象,来覆盖默认行为
join() 等待线程运行结束
join(long millis) 等待线程运行结束,最多等待 millis毫秒
join(long millis,int nanos) 等待线程运行结束,最多等待 millis毫秒,nanos纳秒
getId() 获取线程长整型的 id id 唯一
getName() 获取线程名
setName(String name) 修改线程名
getPriority() 获取线程优先级
setPriority(int newPriority) 修改线程优先级 java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率
static yield() 提示线程调度器让出当前线程对CPU的使用 主要为了调试和测试
static sleep(long millis) 使得当前线程阻塞millis毫秒
static sleep(long millis, int nanos) 使得当前线程阻塞millis毫秒加上nanos纳秒
static   currentThread() 获取当前正在执行的线程
isAlive() 判断线程存活状态
interrupt() 打断线程 如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置 打断标记
isInterrupted() 判断是否被打断 不会清除打断标记
static interrupted() 判断当前线程是否被打断 会清除打断标记
getState() 获取线程状态 Java 中线程状态是用 6 个 enum 表示,分别为:

NEW, RUNNABLE, BLOCKED, WAITING,

TIMED_WAITING, TERMINATED



二、start方法



1.演示代码

 Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("running...");
            }
        }; 

        t1.start();
        t1.start();

        /**
         * 结果
         * Exception in thread "main" java.lang.IllegalThreadStateException
         * 	at java.lang.Thread.start(Thread.java:705)
         * 	at cn.itcast.test.Test5.main(Test5.java:17)
         * 17:48:15.878 c.Test5 [t1] - running...
         */



2.说明



通过start源码可以看出,当第二次调用start的时候 threadStatus等于5,即不等于0所以就抛出IllegalThreadStateException异常。start方法中最核心的就是调用了start0()方法,而start0 源码为:private native void start0();jvm会调用native方法执行线程run方法。

三、run()方法

1、演示代码

  public static void main(String[] args) {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("running 继承方式...");
            }
        };
        t1.run();
        t1.start();
        Thread t2 = new Thread(()->{
            log.debug("running Runnable接口实现方式...");
        },"t2");
        t2.run();
        t2.start();
        /**
         * 结果:
         * 19:24:12.739 c.Test5 [main] - running 继承方式...
         * 19:24:12.742 c.Test5 [t1] - running 继承方式...
         * 19:24:12.772 c.Test5 [main] - running Runnable接口实现方式...
         * 19:24:12.773 c.Test5 [t2] - running Runnable接口实现方式...
         */

    }

2、说明

如果通过线程对象直接调用run方法,那么就只是调用了一个普通的run方法,不会启动多线程。只有通过start方法才能启动线程,run方法是由jvm调用的。Thread方法中的run方法的源代码如下所示:

如果通过继承的方式创建线程并重写run方法,那么jvm调用的是子类的run方法,Thread类中的run方法就没什么意义。如果通过实现Runnable接口的方式实现多线程,那么就会调用Thread中的run方法,该方法的逻辑很简单,就是判断一下传入Thread类中Runnable接口实现类对象target是否为空,如果不为空就调用该对象的run方法。target是Thread中的成员变量,当创建线程时,把Runnable接口的实现类对象传到Thread构造函数中,该构造函数会调用内部私有方法init进行赋值

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
         
        if (name == null) {
           //如果线程名字为空,则抛出异常,这也说明线程都要由名字
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        //target 成员变量赋值
        this.target = target;
        setPriority(priority);
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

四、join()、join(n)、join(n,m)方法

1、演示代码

   public static void main(String[] args) throws InterruptedException {
        log.debug("开始");
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("结束");
            r = 10;
        },"t1");
        t1.start();

         t1.join();
        log.debug("结果为:{}", r);
        log.debug("结束");

        /**
         * 不使用join()方法时候的结果为:
         * 21:27:50.683 c.Test10 [main] - 开始
         * 21:27:50.714 c.Test10 [t1] - 开始
         * 21:27:50.714 c.Test10 [main] - 结果为:0
         * 21:27:50.715 c.Test10 [main] - 结束
         * 21:27:51.720 c.Test10 [t1] - 结束
         * 使用join()方法后的结果
         * 21:28:55.345 c.Test10 [main] - 开始
         * 21:28:55.378 c.Test10 [t1] - 开始
         * 21:28:56.380 c.Test10 [t1] - 结束
         * 21:28:56.380 c.Test10 [main] - 结果为:10
         * 21:28:56.382 c.Test10 [main] - 结束
         */
    }

2、说明

join方法的作用是主线程(调用join方法线程)等待子线程(被调用join方法的线程)的终止。也就是说主线程的代码块中,如果碰到了t.join()方法,此时主线程需要等待(阻塞),等待子线程结束了 ,才能继续执行t.join()之后的代码块。对应上边演示代码就是当main线程执行到t1.join()的时候,需要等待t1线程执行完成后再继续执行后边的代码。join()与join(n)方法的区别,就是当主线程等待n毫秒后,如果子线程还没执行完那么主线程也不会等待了。如果子线程执行时间小于n,那么子线程执行完成后主线程立马就可以执行。至于join(n,m)带两个参数的方法其实相比较join(n)没有多大区别,因为join(n,m)内部也调用join(n),具体细节看源码

    public final void join() throws InterruptedException {
        //调用带有一个形参的join方法
        join(0);
    }

    public final synchronized void join(long millis, int nanos)
    throws InterruptedException {
         //对参数millis合法性进行检查,如果小于0那么该参数为非法参数就会抛出异常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        //对参数nanos 合法性进行检查,如果小于0那么该参数为非法参数就会抛出异常
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
        //如果纳秒数大于等于500000或者毫秒数为0但是纳秒数不为0,那么把毫秒数参数millis加1
        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }
        
        //调用只有一个参数的join方法,此时millis最多比调用该方法时多1毫秒
        join(millis);
    }


   public final synchronized void join(long millis)
    throws InterruptedException {
        //记录当前时间毫秒数
        long base = System.currentTimeMillis();
        //定义变量now,变量nowjoin代表该join方法已经执行的毫秒数
        long now = 0;
         //对参数合法性进行检查,如果小于0那么该参数为非法参数就会抛出异常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        //如果参数等于0
        if (millis == 0) {
            //只要该线程处于活动状态那么进入while循环体
            while (isAlive()) {
          //如果该线程还存活,那么调用该线程join方法的线程,就会被置为阻塞状态(TIMED_WAITING)
                wait(0);
            }
        } else {
             //如果参数不等于0,其实到这一步就代表参数大于0
            //只要该线程处于活动状态那么进入while循环体
            while (isAlive()) {
                 //计算参数millis与now的差值
                long delay = millis - now;
                 //如果差值delay小于等于零(主线程阻塞的时间大于等于millis 毫秒),
                 //那么就执行break,即跳出循环,
                 //这也就代表这join方法执行完毕
                if (delay <= 0) {
                    break;
                }
                //主线程阻塞(TIMED_WAITING)dealy毫秒,
               //但此时主线程可能在小于dealy毫秒的时候被唤醒
                wait(delay);
                
                //无论主线程是等待时间够了,还是在等待的中途被打断了
                //now 变量都会被重新赋值,值为当前时间毫秒数减去刚进入该方法的时间数
                //即now变量代表着join方法已经执行的毫秒数
               //赋值完成后会继续进行下一轮的while循环
                now = System.currentTimeMillis() - base;
            }
        }
    }

当主线程调用t1线程的join方法,那么此时主线程就会获得线程对象t1的锁,带主线程被wait后那么主线程会让出cpu及线程对象t1的锁。

如果线程t1还没有调用start方法启动,就调用t1的jion方法,是无效的,因为此时t1线程的isAlive()为false,即该线程还不是处于活动状态,此时就不会阻塞主线程。

五、getId()方法

1、演示代码

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread("t1"){
            @Override
            public void run() {
                log.debug("运行多线程");
            }
        };
        log.debug(t.getId()+"");
        t.start();
        log.debug(t.getId()+"");
        /**
         * 结果:
         * 23:21:42.040 c.Test1 [main] - 20
         * 23:21:42.042 c.Test1 [main] - 20
         * 23:21:42.043 c.Test1 [t1] - 运行多线程
         */
    }

2、说明

无论该线程是否启动,该线程的id都已经生成了。这是因为当创建线程对象时,构造方法会调用内部的init方法,该方法中就对线程id做了赋值,也就是说线程对象创建后线程id就有值了。


private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {

        /* Set thread ID */
        tid = nextThreadID();
    }

private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }
    /* For generating thread ID */
private static long threadSeqNumber;

 public long getId() {
        return tid;
    }

init(ThreadGroup g, Runnable target, String name,  long stackSize, AccessControlContext acc)方法完整代码在上边说明run()方法时已经展示了完整的代码了,所以此处省略一些代码,getId方法其实就是返回了Thread成员变量tid的值,而tid的值在init中被赋值。其实tid的值就是Thread 静态成员变量threadSeqNumber值加1,应为threadSeqNumber为静态的所以这也就能解释为什么该线程的id不是1而是20的原因了。

六、getName()及setName(String name)方法

1、演示代码

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(){
            @Override
            public void run() {
                log.debug("运行多线程");
            }
        };
        log.debug(t.getName());
        t.setName("t1");
        log.debug(t.getName());
        t.start();

        /**
         * 结果:
         * 23:40:02.851 c.Test1 [main] - Thread-0
         * 23:40:02.853 c.Test1 [main] - t1
         * 23:40:02.854 c.Test1 [t1] - 运行多线程
         */
    }

2、说明

getName()及setName(String name)做用就是获取线程名字和设置线程名字

    public final String getName() {
        return name;
    }

    public final synchronized void setName(String name) {
        checkAccess();
         //参数检查
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
         //成员变量name重新赋值
        this.name = name;
         //如果threadStatus不等于0,即该线程对象已经创建了并启动了
        if (threadStatus != 0) {
            //设置线程名称
            setNativeName(name);
        }
    }

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(String name) {
        init(null, null, name, 0);
    }


线程可以通过setName命名,也可以在创建线程的时候直接命名,如果线程没有刻意的命名,那么jdk会给该线程命名,命名规则为”Thread-” + nextThreadNum()

七、getPriority()及setPriority(int newPriority)方法

1、演示代码

 public static void main(String[] args) {
        Runnable task1 = () -> {
            int count = 0;
            for (;;) {
                System.out.println("---->1 " + count++);
            }
        };
        Runnable task2 = () -> {
            int count = 0;
            for (;;) {
                System.out.println("              ---->2 " + count++);
            }
        };
        Thread t1 = new Thread(task1, "t1");
        Thread t2 = new Thread(task2, "t2");

        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        t2.start();
        /**
         * 不设置优先级部分结果
         *
         * ---->1 1697629
         * ---->1 1697630
         * ---->1 1697631
         *               ---->2 1100251
         *               ---->2 1100252
         *设置优先级后部分结果
         * ---->1 1024957
         * ---->1 1024958
         * ---->1 1024959
         *               ---->2 2245023
         *               ---->2 2245024
         *               ---->2 2245025
         */
    }

2、说明

getPriority()是返回该线程的优先级,setPriority(int newPriority)是设置线程的优先级,通过演示代码可以看出,对于优先级高的线程,执行的机率就会低一些,但这不代表低优先级的线程不能被执行。也不能代表低优先级的线程一定是在高优先级的线程后边执行。线程创建时会继承父线程的优先级。

 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
         
        Thread parent = currentThread();
       
        this.priority = parent.getPriority();
         
        setPriority(priority);
        
    }
    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        //对参数进行校验
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
         //如果当前线程的线程组不为空
        if((g = getThreadGroup()) != null) {
             //如果传入的优先级大于线程组中线程优先级最大值
            if (newPriority > g.getMaxPriority()) {
                //newPriority 重新赋值为当前线程组中线程优先级的最大值
                newPriority = g.getMaxPriority();
            }
            //调用本地方法,设置线程的优先级,并且把Thread成员变量重新赋值为newPriority
            setPriority0(priority = newPriority);
        }
    }

    public final int getPriority() {
        return priority;
    }


    /**
     * The minimum priority that a thread can have.
     * 最小优先级
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     * 默认优先级
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     * 最大优先级
     */
    public final static int MAX_PRIORITY = 10;

八、yield() 方法

1、演示代码

public static void main(String[] args) {
        Runnable task1 = () -> {
            int count = 0;
            for (;;) {
                System.out.println("---->1 " + count++);
            }
        };
        Runnable task2 = () -> {
            int count = 0;
            for (;;) {
                Thread.yield();
                System.out.println("              ---->2 " + count++);
            }
        };
        Thread t1 = new Thread(task1, "t1");
        Thread t2 = new Thread(task2, "t2");
        t1.start();
        t2.start();
        /**
         *运行结果:
         *               ---->2 221719
         *               ---->2 221720
         * ---->1 520559
         * ---->1 520560
         */
    }

2、说明

public static native void yield();

调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,把执行机会让给优先级相同或更高的线程,如果队列中没有同优先级的线程则忽略此方法。

九、sleep(long millis)、sleep(long millis, int nanos) 方法

1、演示代码

 public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("enter sleep...");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    log.debug("wake up...");
                    e.printStackTrace();
                }
                log.debug("enter sleep end...");
            }
        };
        t1.start();
        log.debug("main thread run...");
        /**
         * 运行结果:
         * 07:42:41.349 c.Test7 [main] - main thread run...
         * 07:42:41.349 c.Test7 [t1] - enter sleep...
         * 07:42:43.362 c.Test7 [t1] - enter sleep end...
         */
    }

2、说明

通过时间戳可以看出sleep起作用,调用sleep会让当前线程从 Running 进入Timed Waiting 状态(阻塞),睡眠结束后的线程未必会立刻得到执行。sleep(long millis)方法也为本地方法。

    public static native void sleep(long millis) throws InterruptedException;

    
    public static void sleep(long millis, int nanos)
    throws InterruptedException {
         //参数合法性校验,如果millis小于0则会抛出异常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
         //参数合法性校验,nanos如果小于0,或者大于999999则抛出异常
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
         //如果nanos大于等于500000 或者毫秒数为0但纳秒数不为0则millis加1
        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        //调用本地方法sleep(long millis),此时毫秒数最多比原有形参数多1毫秒
        sleep(millis);
    }

十、currentThread() 方法

1、演示代码

 public static void main(String[] args) throws InterruptedException {
        Thread thread = Thread.currentThread();
        thread.setName("main 线程");
        log.debug("main 运行,,,,");
        //结果:08:00:32.071 c.Test8 [main 线程] - main 运行,,,,
    }

2、说明

currentThread方法也是本地方法

public static native Thread currentThread();

十一、isAlive() 方法

1、演示代码

 public static void main(String[] args) throws InterruptedException {
         Thread t = new Thread("t1"){
             @Override
             public void run() {
                  log.debug("run 方法里:"+String.valueOf(Thread.currentThread().isAlive()));
                 try {
                     Thread.sleep(2000);
                     log.debug("t1主线程睡眠后:"+String.valueOf(Thread.currentThread().isAlive()));
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } 
             }
         };
        log.debug("线程对象创建后:"+String.valueOf(t.isAlive()));
        t.start();
        log.debug("线程调用start后:"+String.valueOf(t.isAlive()));
         Thread.sleep(3000);
        log.debug("主线程睡眠1S后:"+String.valueOf(t.isAlive()));
        /**
         * 运行结果:
         * 08:31:45.926 c.Test8 [main] - 线程对象创建后:false
         * 08:31:45.928 c.Test8 [main] - 线程调用start后:true
         * 08:31:45.928 c.Test8 [t1] - run 方法里:true
         * 08:31:47.944 c.Test8 [t1] - t1主线程睡眠后:true
         * 08:31:48.940 c.Test8 [main] - 主线程睡眠1S后:false
         */ 
    }

2、说明

isAlive()方法判读线程是否存活(还没有运行完毕)该方法也是本地方法

public final native boolean isAlive();

十二、interrupt()、isInterrupted()、interrupted()方法

1、演示代码

//打断阻塞状态    
public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            try {

                Thread.sleep(5000); // wait, join

            } catch (InterruptedException e) {
                log.debug("sleep interrupt....");
                log.debug("sleep 之后打断标志:{}",Thread.currentThread().isInterrupted());
                e.printStackTrace();
            }
        },"t1");

        t1.start();


        log.debug("interrupt");
         t1.interrupt();


        /**
         * 结果:
         * 20:59:31.757 c.Test11 [main] - interrupt
         * 20:59:31.757 c.Test11 [t1] - sleep...
         * 20:59:31.761 c.Test11 [t1] - sleep interrupt....
         * 20:59:31.761 c.Test11 [t1] - sleep 之后打断标志:false
         * java.lang.InterruptedException: sleep interrupted
         * 	at java.lang.Thread.sleep(Native Method)
         * 	at cn.itcast.test.Test11.lambda$main$0(Test11.java:13)
         * 	at java.lang.Thread.run(Thread.java:745)
         */
    }
//打断正常运行的线程
public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while(true) {
                boolean interrupted = Thread.currentThread().isInterrupted();
                log.debug("线程"+Thread.currentThread().getName()+"在运行");
                if(interrupted) {
                    log.debug("被打断了, 退出循环");
                    break;
                }
            }
        }, "t1");
        t1.start();
        log.debug("interrupt");
        t1.interrupt();

        /**
         * 运行结果:
         * 21:24:11.495 c.Test12 [main] - interrupt
         * 21:24:11.495 c.Test12 [t1] - 线程t1在运行
         * 21:24:11.498 c.Test12 [t1] - 线程t1在运行
         * 21:24:11.498 c.Test12 [t1] - 被打断了, 退出循环
         */
    }
private static void test4() {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                log.debug("park..."+i);
                LockSupport.park();
               // Thread.interrupted()会清除打断标志
                log.debug("打断状态:{}", Thread.interrupted());
                //如果打断标记已经是 true, 则 park 会失效
                // log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
            }
        });
        t1.start();
        sleep(1);
        t1.interrupt();
        //如果打断标记已经是 true, 则 park 会失效
        /**
         * 运行结果:
         *21:39:03.888 c.Test14 [Thread-0] - park...0
         * 21:39:04.896 c.Test14 [Thread-0] - 打断状态:true
         * 21:39:04.898 c.Test14 [Thread-0] - park...1
         * 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
         * 21:39:04.898 c.Test14 [Thread-0] - park...2
         * 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
         * 21:39:04.898 c.Test14 [Thread-0] - park...3
         * 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
         * 21:39:04.898 c.Test14 [Thread-0] - park...4
         * 21:39:04.898 c.Test14 [Thread-0] - 打断状态:true
         */

        //Thread.interrupted()会清除打断标志
        /**
         *21:41:19.075 c.Test14 [Thread-0] - park...0
         * 21:41:20.081 c.Test14 [Thread-0] - 打断状态:true
         * 21:41:20.083 c.Test14 [Thread-0] - park...1
         */
    }

    private static void test3() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("park...");
            LockSupport.park();
            log.debug("unpark...");
            log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
        }, "t1");
        t1.start();

         sleep(1);
         t1.interrupt();

        /**
         * 运行结果:
         * 21:34:59.118 c.Test14 [t1] - park...
         * 21:35:00.132 c.Test14 [t1] - unpark...
         * 21:35:00.133 c.Test14 [t1] - 打断状态:true
         */
    }

2、说明

处于阻塞的线程,即在执行Object对象的wait()、wait(long)、wait(long, int),或者线程类的join()、join(long)、join(long, int)、sleep(long)、sleep(long,int)方法后线程的状态,当线程调用interrupt()方法后,这些方法将抛出InterruptedException异常,并清空线程的中断状态,即isInterrupted()返回false,也就是说interrupt()可以中断阻塞状态,但是要注意的interrupt()方法不是中断线程执行,如果想要通过interrupt()方法中断线程,那就需要配合着isInterrupted()方法,通过代码逻辑来实现,可以参考着上边的演示代码中的“打断正常运行的线程”的代码。另外isInterrupted()、interrupted() 两个方法都可以查看线程是否被打断,但不同的是interrupted()返回是否被打断后,会清除打断标记。 通过如下代码可以理解两个方法区别:

   private static void test4() {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i <3; i++) {
                log.debug("park..."+i);
                //如果打断标记已经是 true, 则 park 会失效
                log.debug("打断状态isInterrupted1:{}", Thread.currentThread().isInterrupted());
                LockSupport.park();
               // Thread.interrupted()会清除打断标志
                log.debug("打断状态:{}", Thread.interrupted());
                log.debug("打断状态isInterrupted2:{}", Thread.currentThread().isInterrupted());
                Thread.currentThread().interrupt();
                log.debug("打断状态isInterrupted3:{}", Thread.currentThread().isInterrupted());
            }
        });
        t1.start();
        sleep(1);
        t1.interrupt();
        /**
         * 运行结果:
         * 22:10:00.242 c.Test14 [Thread-0] - park...0
         * 22:10:00.244 c.Test14 [Thread-0] - 打断状态isInterrupted1:false
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态:true
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted2:false
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted3:true
         * 22:10:01.252 c.Test14 [Thread-0] - park...1
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted1:true
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态:true
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted2:false
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted3:true
         * 22:10:01.252 c.Test14 [Thread-0] - park...2
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted1:true
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态:true
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted2:false
         * 22:10:01.252 c.Test14 [Thread-0] - 打断状态isInterrupted3:true
         */

    }
//本地方法,通过参数ClearInterrupted来控制是否重置中断状态,false就不重置
private native boolean isInterrupted(boolean ClearInterrupted);

public boolean isInterrupted() {
        return isInterrupted(false);
}

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
}

十三、getState() 方法

1、演示代码

public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        log.debug("t1 state: {}", t1.getState());

        t1.start();
        log.debug("t1 state: {}", t1.getState());

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("t1 state: {}", t1.getState());

        t1.join();

        log.debug("t1 state: {}", t1.getState());

        /**
         * 运行结果:
         * 22:24:31.957 c.Test6 [main] - t1 state: NEW
         * 22:24:31.961 c.Test6 [main] - t1 state: RUNNABLE
         * 22:24:32.461 c.Test6 [main] - t1 state: TIMED_WAITING
         * 22:24:33.964 c.Test6 [main] - t1 state: TERMINATED
         */
    }

2、说明

getState() 方法作用是获取线程状态    Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING,TIMED_WAITING, TERMINATED,演示代码演示了4种状态,对于线程的状态后边会单独整理一篇文章。

    public State getState() {
        // get current thread state
        return sun.misc.VM.toThreadState(threadStatus);
    }

    public static State toThreadState(int var0) {
        if ((var0 & 4) != 0) {
            return State.RUNNABLE;
        } else if ((var0 & 1024) != 0) {
            return State.BLOCKED;
        } else if ((var0 & 16) != 0) {
            return State.WAITING;
        } else if ((var0 & 32) != 0) {
            return State.TIMED_WAITING;
        } else if ((var0 & 2) != 0) {
            return State.TERMINATED;
        } else {
            return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
        }
    }

 public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }



总结

以上就是对Thread中常用的方法做一个简单讲解,以便学习。在Thread中还有几个已经过时的方法,分别为:

stop() 停止线程运行
suspend() 挂起(暂停)线程运行
resume() 恢复线程运行

这些方法已过时,容易破坏同步代码块,造成线程死锁



版权声明:本文为lcgskycby原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。