Java多线程学习(三)Thread基本函数详解(sleep、yield、join、interrupt、守护线程、优先级)

一、图片总结:

1.1 补充知识

下图是线程的的六种状态

  1. 初始态
  2. 运行态(就绪是指等待CPU分配执行)
  3. 阻塞态
  4. 等待态
  5. 超时等待态
  6. 终止态

下图取之Java线程状态
在这里插入图片描述

1.2 函数整体总结

在这里插入图片描述

二、sleep、yield、join

2.1 sleep:

  • Api:
  1. sleep(long millis) //参数为毫秒
  2. sleep(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒
  • 作用: sleep就是让线程睡眠,交出CPU

注意点:但是值得注意的是它不会释放锁(即如果该线程持有该对象的锁,那么sleep后其他线程也无法访问该对象。)

2.2 yield

  • Api:
  1. yield()
  • 作用: yield 让当前线程交出CPU,但是不能控制时间

注意点: 不会释放锁,但是值得注意的是yield只能让等于或大于自己优先级的线程有机会获得CPU执行机会

2.3 join

  • 结论:先说结论
  1. join 是通过wait来实现的。
  2. 但是join不会释放锁,因为他wait的线程是你执行thread.join所在的线程(一般是main线程)
  • Api:
  1. join()
  2. join(long millis) //参数为毫秒
  3. join(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒
  • 作用:让当前线程等待子线程结束之后才能运行

注意点:join实现的顺序如下
1.假设在main线程里运行了子线程A
2.接着设置 A.join()
3.接着main线程会处于waiting状态
4.直到子线程完成后通知main线程结束等待
-------------特别注意的一个概念----------------->
1.主线程调用的方法就是主线程获得锁,子线程run方法里的调用才是子线程获得锁。
2.所以join通过wait来等待的是主线程,子线程是不会释放锁的

  • 例子
lic class JoinTest {
    public static int a = 0;
    public static void main(String ...args) throws InterruptedException {


        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++)
                    a++;
            }
        });
        
        thread.start();

        //在main线程里执行了join,所以main线程获得了join的锁
        //后面join源码分析里执行wait是main线程(不要搞乱了)
        thread.join();
        println(a);


    }
//如果不加 join 正常情况下应该是小于10的
//但是加了 join 后,它会等待thread线程执行结束后再执行主线程
//所以答案等于10
  • 源码解析
 public final void join(long millis) throws InterruptedException {
        synchronized(lock) {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
        //判断子线程是否执行完毕,如果执行完毕的话进行等待
        //这边等待对象是你执行 thread.join 所在的线程 即main
        //这边只要子线程没执行完毕就无限循环
            while (isAlive()) {
                lock.wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                lock.wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
        }
    }

三、interrupt

  • Api
  1. thread.interrupt() 通知线程中断(只是一个信号,真正如何处理还是需要自己判断)
  2. Thread.interrupted() 得到线程是否中断的状态并且重置状态(false)
  3. Thread.currentThread().isInterrupted()得到线程是否中断的状态
  • 注意

调用interrupt()方法,立刻改变的是中断状态,但如果不是在阻塞态,就不会抛出异常;如果在进入阻塞态后,中断状态为已中断,就会立刻抛出异常(阻塞状态 run方法无法执行得通过其他方法来判断)

  • 例子
    这边举一个正在阻塞状态中的例子,如果正常运行的话Run方法会正常执行只用通过判断isInterrupted就可以来

业务重点
其中sleep被阻塞100秒这时候如果提前终止使用isInterrupted是不行的。我们通过阻塞时执行interrupt()会抛异常的特性来完成该操作,捕捉到异常后,会提前结束阻塞状态,所以更改stop的属性来挑出循环,等待run方法执行完毕。

 static boolean stop = true;

    public static void main(String... args) {


        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
            
                while (stop) {
                    try {
                        Thread.sleep(100000);
                    } catch (InterruptedException e) {
                        stop = false;
                    }

                }
            }
        });

        thread.start();
        thread.interrupt();
        
    }

四、优先级

  • Api
  1. setPriority
  • 作用:
    设置优先级,高优先级被优先执行的几率更大

  • 优先级等级(1-10):

  1. 最低优先级 1:Thread.MIN_PRIORITY
  2. 最高优先级 10:Thread.MAX_PRIORITY
  3. 普通优先级 5:Thread.NORM_PRIORITY

如果无设置优先级,默认时父线程的优先级,比如我们平时在主线程创建线程优先级都是5.

五、守护线程

  • 补充知识:
    守护线程是为其他线程服务的,若只剩下守护线程,那么守护线程就会自动中断。
  • Api
  1. setDaemon(true)
  • 作用:设置为守护线程
  • 注意点
  1. thread.setDaemon(true)必须在thread.start()之前设置
  2. 你不能把正在运行的常规线程设置为守护线程。
  3. 在Daemon线程中产生的新线程也是Daemon的
    4.守护线程中不能做重要的操作,因为它随时可能中断
  • 例子
      Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread daemonThread = new Thread(() -> {

                    while (true){
                        System.out.print("我是守护线程" + "\n");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }


                });
                //设置为守护线程
                daemonThread.setDaemon(true);
                daemonThread.start();
                
                System.out.print("开始运行了" + "\n");


            }
        });
        
        thread.start();
//正常来说daemonThread会一直循环
//当时当他设置为守护线程后 thread执行结束后 daemonThread也随之结束。

六、resume()、suspend()、stop()

resume():重启线程
suspend():挂起线程
stop():停止线程
这三个方法都可能会出现一些不可预料的问题, 所以被废弃了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值