线程状态以及sleep()、wait()、join()、yield()等方法

本文详细探讨了Java中sleep、wait、yield和join方法在多线程编程中的应用和区别。sleep会使线程进入阻塞状态并指定时间后恢复,wait需在同步块中使用并与对象锁关联,yield则是线程间礼让CPU时间片,join用于主线程等待其他线程执行完毕。通过实例代码分析了它们的工作原理和使用场景。
摘要由CSDN通过智能技术生成


在这里插入图片描述

一、sleep和wait的共同点和区别

共同点:

  1. 两个方法都会使线程进入阻塞状态,都可以被interrupt()中断,被中断后都会抛出异常

区别:

  1. sleep是Thread类的方法,而wait是object的方法
  2. 因为sleep必须指定时间,而wait是可以不需要指定时间的,所以sleep不需要被唤醒,而wait需要
  3. wait必须和sychronized共同使用,而sleep不需要(join底层是wait,但是不需要在synchronized中使用,因为join方法本身就带有synchronized)
  4. wait会释放锁,而sleep不会释放锁。

二、yield

对于yield方法,比较容易理解,只是简单地对于CPU时间片的“礼让”,除非循环yield,否则一次yield,可能下次该线程仍旧可能会抢占到CPU时间片,可能方法调用和不调用没差别

public static void main(String argv[]) throws IOException, OfficeException {


    Thread thread1 = new Thread(()->{
        System.out.println(Thread.currentThread().getName()+"-----第一阶段开始!");

        try {
            Thread.sleep(3);
            System.out.println(Thread.currentThread().getName()+"-----第一阶段结束!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    },"Thread111");

    thread1.start();

    Thread thread2 = new Thread(()->{
        while (!Thread.State.TERMINATED.equals(thread1.getState())){
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+"-----等待线程Thread111第一阶段结束。thread1状态:"+thread1.getState());
        }
        System.out.println(Thread.currentThread().getName()+"-----执行完成!");
    },"Thread222");

    thread2.start();

}

输出:

Thread111-----第一阶段开始!
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TIMED_WAITING
Thread111-----第一阶段结束!
Thread222-----等待线程Thread111第一阶段结束。thread1状态:TERMINATED
Thread222-----执行完成!

三、join

从以下代码我们可以看出,使用了join方法,主线程等待thread1执行结束完成之后才执行。

public static void main(String argv[]) throws IOException, OfficeException {

     Thread thread1 = new Thread(()->{
         for (int k = 0; k < 5; k++) {
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             System.out.println(Thread.currentThread().getName()+"woking");
         }
     },"thread1");

     thread1.start();

     try {
         thread1.join();
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
     System.out.println("main结束");

 }
thread1woking
thread1woking
thread1woking
thread1woking
thread1woking
main结束

主线程main中调用启动线程(调用start),然后调用该线程的join方法,可以达到主线程等待工作线程运行结束才执行的效果,并且join要在start调用后
为什么?接下来看join代码

public final synchronized void join(long millis)
   throws InterruptedException {
       long base = System.currentTimeMillis();
       long now = 0;

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

       if (millis == 0) {
           while (isAlive()) {
               wait(0);
           }
       } else {
           while (isAlive()) {
               long delay = millis - now;
               if (delay <= 0) {
                   break;
               }
               wait(delay);
               now = System.currentTimeMillis() - base;
           }
       }
   }

从以上代码我们可以看出join底层使用的是wait方法,并且做了isAlive判断,也就是this.isAlive,也就是当前线程alive(已启动,未终止),那么将持续等待,等待的这个临界资源就是这个我们创建的线程。

所以这两段代码的含义是:

  1. 该线程是否存活,如果存活,那么调用join方法的线程会在这个对象上进行等待(进入该对象的等待集)
  2. 也就是说调用一个线程的join方法,那么就在这个线程上等待,这个线程对象就是我们的锁对象。
  3. 还有一个问题是既然底层是wait方法,但上面代码又没有调用notify和notityall方法,wait也不会自己醒过来,那不是出错了吗。这是因为线程执行完成之后会调用notify和notifyall方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值