美文网首页Java学习笔记
Thread类中控制线程的方法

Thread类中控制线程的方法

作者: 爱说的夏老师 | 来源:发表于2017-07-03 17:16 被阅读32次

这篇文章中不会介绍sleepwait, 会在其他的文章中介绍

1. stop

停止线程, 不推荐使用.

JDK中已经标识为@Deprecated, 因为太暴力, 无论线程运行到什么状态, 都会强制停止, 可能会导致数据的不一致, 并且不会抛出异常.

2. interrupt

中断线程

2.1 非阻塞状态的线程

相当于一个中断的标志位, 调用之后, 只是把这个标志位改成true.
可以通过interrupted()这个方法来判断中断状态.

也就是说, 单纯的调用这个interrupt()方法, 是不会使得线程的运行中断的, 如果要中断线程的运行, 可以通过这样的代码来控制

public void run(){ 
    while(true){ 
        if(Thread.currentThread().isInterrupted())
        { 
           System.out.println("Interruted!"); 
           break; 
        } 
        Thread.yield(); //这里可以是正常的线程执行操作
    } 
}

2.2 阻塞状态的线程

对于可取消的阻塞状态中的线程, 比如等待在这些函数上的线程, Thread.sleep(), Object.wait(), Thread.join(), 这个线程收到中断信号后, 会抛出InterruptedException, 同时会把中断状态置回为false.
理论上所有会throws InterruptedException的方法都是可以取消阻塞状态的.

对于取消阻塞状态中的线程,可以这样写代码

public void run(){
    while(true){
        if(Thread.currentThread().isInterrupted()){
            System.out.println("Interruted!");
            break;
        }
        try {
           Thread.sleep(2000);
        } catch (InterruptedException e) {
           System.out.println("Interruted When Sleep");
           //设置中断状态,抛出异常后会清除中断标记位
           Thread.currentThread().interrupt();
        }
        Thread.yield();//这里可以是正常的线程执行操作
    }
}

sleep的中断比较容易, 但是wait方法如果被中断, 不一定会马上抛出异常, 如果获取不到锁对象, 就会继续等待, 知道获取之后才会抛出InterruptedException.

此外, interrupt()还可以在使用Lock对象的时候, 解决死锁的问题(可以参考Lock的lockInterruptibly()
方法)

3. suspend和resume

线程挂起(suspend)和继续执行(resume)

这两个方法都是Deprecated方法,不推荐使用。
原因在于,suspend不释放锁,因此如果suspendsynchronized块中执行的,并且也没有其他线程来执行resume方法, 这个线程将一直占有这把锁,造成死锁发生。

4. yield

让出CPU资源

这个让出只是一下, 执行完之后, 线程并不是变成等待状态, 而是从 "运行状态" 转换为 "就绪状态", 也就是说可能这个线程还是可能会马上抢占到CPU的资源
官方说是可用于debug和test, 基本找不到使用的场景...

5. join

等待其他线程结束

join的本质

while (isAlive()) {
    wait(0);
}

详细的可以查看join的源码

public static void main(String[] args) throws Exception {
    Thread r1 = new Thread(new MyThread());
    r1.start();
    r1.join();//等待r1线程执行完之后,才会继续执行下面的语句
    System.out.println("主线程结束");
}

上面的代码, 主线程在执行r1.join()的时候就会判断r1.isAlive(), 如果r1线程还活着, 就wait(0)

既然是wait操作, 肯定会有锁对象. join方法是synchronized的, 所以调用这个方法的对象就是锁对象. 上面这个锁对象就是r1这个线程对象

同样, 既然是wait, 肯定会有对应的notify来唤醒这个wait

那么问题是哪里调用了notify呢?

在join方法的javadoc中找到了解释:

Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.

This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

意思是在每个线程结束之后, 都有调用this.notifyAll(), 那么这个操作可以理解为是由JVM自动完成的动作. 上面的代码则会在r1这个线程结束之后, JVM自动调用this.notifyAll(), 这里的this相当于r1, 然后把所有等待r1这个锁对象的线程给唤醒.

所以javadoc中还给了我们一个建议,不要使用wait和notify/notifyAll在线程实例上。因为jvm会自己调用,有可能与你调用期望的结果不同。

参考资料

  1. https://my.oschina.net/hosee/blog/599000

相关文章

  • 【多线程】——2.线程的创建

    线程的创建 Thread类: 继承Thread类的方式创建线程 重写run方法,在run方法内想做需要在子线程中完...

  • 多线程3:Thread中的静态方法

    Thread类中的静态方法 Thread类中的静态方法表示操作的线程是"正在执行静态方法所在的代码块的线程"。为什...

  • Runnable和Thread的异同

    创建线程 第一种方式:继承Thread类 定义类继承Thread 复写Thread类中的run方法 调用线程的st...

  • Java多线程常用操作方法

    线程的命名和取得 Thread类中的线程名称操作方法 构造方法: public Thread(Runnable t...

  • Thread类中控制线程的方法

    这篇文章中不会介绍sleep和wait, 会在其他的文章中介绍 1. stop 停止线程, 不推荐使用. JDK中...

  • [java]9、多线程

    1、开启新线程 1)、创建一个Thread类的子类2)、在Thread类的子类中重写Thread类中的run方法,...

  • 详解Thread多线程

    如何创建线程 Java 中创建线程的方法有三种:1. 继承 Thread 类创建线程 新建一个类继承 Thread...

  • java多线程2:Thread中的方法

    静态方法: Thread类中的静态方法表示操作的线程是"正在执行静态方法所在的代码块的线程"。 为什么Thread...

  • java实现多线程

    一.java创建线程的方法1.Thread类派生①.继承Thread类②.重写run()方法、该方法用来描述该线程...

  • 创建线程的3种方法

    转载 Java创建线程的3中方法 继承Thread类创建线程类 通过Runnable接口创建线程类 通过Calla...

网友评论

    本文标题:Thread类中控制线程的方法

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