首页 > 技术文章 > Thread中方法:setDaemon, join, 中断,yield

Stephanie-boke 2020-02-17 05:02 原文

Thread中方法

  • 注意为什么sleep()、currentThread()、interrupted()、yield()这些方法是静态方法,因为设计一个线程的run()方法的时候,需要改变当前线程的状态,而当前线程对象未定义完毕无法调用函数,在这种情况下可以直接调动静态方法(等同于当前线程直接调用了该方法),或者调用currentThread()方法来获取当前线程对象。

如:

public static void main(String[] args) {

    Thread t = new Thread(() ->{
        try {
            Thread.sleep(1000);
            int result = A/B;

            //错误:The local variable t may not have been initialized
            t.join();

            System.out.println(result);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    });

1、setDaemon

  • setDaemon(boolean on): 将该线程标记为守护线程或用户线程。
  • 当前线程结束,守护线程也跟着结束
  • 必须在调用start()方法前,调用setDaemon方法

2、 优先级

  • getId(): 返回该线程的标识符。
  • getPriority(): 返回线程的优先级。
  • setPriority(int newPriority): 更改线程的优先级。

3、join

  • join(): 当前线程等待调用该方法线程结束,也就是让“主线程”等待“子线程”结束之后才能继续运行。
  • join(time): 当前线程等到调用该方法多长时间
  • Thread.currentThread().join(): 当前线程等待当前线程的结束,程序处于一直运行的状态
  • 是封装了wait方法
  • join相比wait而言,join是只能让当前线程等待,而wait可以让任意调用这个函数的线程等待。
  • 根据底层实现原理,只要调用这个函数的“子线程”一直没死亡,那么会一直调用这个函数,使得当前线程一直等待,直到“子线程”结束没法在调用join函数为止

更多资料:https://www.cnblogs.com/skywang12345/p/3479275.html

join 和 Daemon对比
join是等待一个线程结束后在执行当前线程,Daemon是守护线程和当前线程并发进行。

4、中断线程 interrupt interrputed

  • 可以中断wait()、sleep()、或者join()方法
  • 中断并不是指直接中断run方法,只是中断wait()、sleep()、join()方法返回一个异常,run还能正常执行
  • interrupt()是实例方法
  • interrupted()是类方法,测试当前线程是否已经中断,底层调用的还是isInterrupted()

https://blog.csdn.net/z69183787/article/details/25076033

https://blog.csdn.net/zhuyong7/article/details/80852884

对比: interrupt() interrupted()

public class CreateThread {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000000);
                    } catch (InterruptedException e) {
                        System.out.println("收到打断信号.");
                        //调用的是实例方法
                        System.out.println(isInterrupted());  //false
                    }
                }
            }
        };

        t.start();
        Thread.sleep(1000);
        System.out.println(t.isInterrupted()); //false
        t.interrupt(); //中断了sleep()方法,但是run()方法并未中断
        System.out.println(t.isInterrupted()); //true

    }       
}

public class CreateThread {
    private static final Object MONITOR = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() ->{
            while(true) {
                synchronized(MONITOR) {
                    try {
                        MONITOR.wait(10);
                    } catch (InterruptedException e) {
                        //调用的是 currentThread().isInterrupted(true)
                        // interrupted是静态方法
                        System.out.println(">> "+Thread.interrupted());
                    }
                }
            }
        });

        t.start();
        Thread.sleep(1000);
        System.out.println(t.isInterrupted());
        t.interrupt();
        System.out.println(t.isInterrupted());

    }       
}

总结:

当Thread是直接重写run方法的时候,可以直接调用isInterrupted方法,相当于this.isInterrupted().

当Thread中传入的是Runnable的时候,在Runnable中的run方法中不能调用实例方法,因为run方法是封装在RUnnable接口里面,在这种情况下,只能调用类的方法。

中断join方法

  • 调用join的是当前线程,不是实例线程

代码示例:

public class CreateThread {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
            public void run() {
                while(true) {

                }
            }
        };

        t.start();
        Thread main = Thread.currentThread();
        Thread t2 = new Thread() {
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //真正要打断的是main线程,才能打断join方法
                main.interrupt();
                System.out.println("Interrupt");
            }
        };

        t2.start();
        try {
            //真正调用join()方法的是当前的线程main,并不是t线程
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }       
}

5、 yield

参考链接:https://blog.csdn.net/dabing69221/article/details/17426953

  • 使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。
  • 让出CPU的执行权
  • 之后所有线程(包括让出的这一线程)同时竞争CPU的执行权。

打个比方:现在有很多人在排队上厕所,好不容易轮到这个人上厕所了,突然这个人说:“我要和大家来个竞赛,看谁先抢到厕所!”,然后所有的人在同一起跑线冲向厕所,有可能是别人抢到了,也有可能他自己有抢到了。我们还知道线程有个优先级的问题,那么手里有优先权的这些人就一定能抢到厕所的位置吗? 不一定的,他们只是概率上大些,也有可能没特权的抢到了。

public class YieldTest extends Thread {

public YieldTest(String name) {
    super(name);
}

@Override
public void run() {
    for (int i = 1; i <= 50; i++) {
        System.out.println("" + this.getName() + "-----" + i);
        // 当i为30时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行)
        if (i == 30) {
            this.yield();
        }
    }
}

public static void main(String[] args) {
    YieldTest yt1 = new YieldTest("张三");
    YieldTest yt2 = new YieldTest("李四");
    yt1.start();
    yt2.start();
}

}

注意:这个不存在线程安全的问题,因为i是局部变量(是每个线程自己所私有的),不存在数据共享的问题。
单个线程也不存在线程安全的问题,代码是按照顺序执行(当然在底层会改变一些数据,但是代码执行的逻辑并未发生改变),所以单个线程会依次打印出1——50

运行结果:

李四-----1
张三-----1
李四-----2
张三-----2
李四-----3
张三-----3
李四-----4
张三-----4
李四-----5
张三-----5
李四-----6
张三-----6
李四-----7
张三-----7
李四-----8
张三-----8
李四-----9
张三-----9
张三-----10
张三-----11
张三-----12
张三-----13
张三-----14
张三-----15
张三-----16
张三-----17
张三-----18
张三-----19
张三-----20
张三-----21
张三-----22
张三-----23
张三-----24
张三-----25
张三-----26
张三-----27
张三-----28
张三-----29
张三-----30
李四-----10
李四-----11
李四-----12
李四-----13
李四-----14
李四-----15
李四-----16
李四-----17
李四-----18
李四-----19
李四-----20
李四-----21
李四-----22
李四-----23
李四-----24
李四-----25
李四-----26
李四-----27
李四-----28
李四-----29
李四-----30
张三-----31
张三-----32
张三-----33
张三-----34
张三-----35
张三-----36
张三-----37
张三-----38
张三-----39
张三-----40
张三-----41
张三-----42
张三-----43
张三-----44
张三-----45
张三-----46
张三-----47
张三-----48
张三-----49
张三-----50
李四-----31
李四-----32
李四-----33
李四-----34
李四-----35
李四-----36
李四-----37
李四-----38
李四-----39
李四-----40
李四-----41
李四-----42
李四-----43
李四-----44
李四-----45
李四-----46
李四-----47
李四-----48
李四-----49
李四-----50

推荐阅读