本章主要对Java中Thread类的基本方法进行学习。

1.序言

Thread类作为线程的基类,提供了一系列方法,主要有:

  • Thread.sleep(long):强制线程睡眠一段时间。
  • Thread.activeCount():获取当前程序中存活的线程数。
  • thread.start():启动一个线程。
  • Thread.currentThread():获取当前正在运行的线程。
  • thread.getThreadGroup():获取线程所在线程组。
  • thread.getName():获取线程的名字。
  • thread.getPriority():获取线程的优先级。
  • thread.setName(name):设置线程的名字。
  • thread.setPriority(priority):设置线程的优先级。
  • thread.isAlive():判断线程是否还存活着。
  • thread.isDaemon():判断线程是否是守护线程。
  • thread.setDaemon(true):将指定线程设置为守护线程。
  • thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。
  • thread.yield():使得当前线程退让出CPU资源,把CPU调度机会分配给同样线程优先级的线程。
  • thread.interrupt():使得指定线程中断阻塞状态,并将阻塞标志位置为true。
  • object.wai()、object.notify()、object.notifyAll():Object类提供的线程等待和线程唤醒方法。

为了便于阅读,将以上所有方法,放在5篇文章中进行学习。

本章主要学习绿色字体标记的方法,其他方法请参加其他章节。

2.yield()方法的理解

先来看yield()方法的定义与注释。

/**
 * A hint to the scheduler that the current thread is willing to yield
 * its current use of a processor. The scheduler is free to ignore this
 * hint.
 * ...
 */
public static native void yield();

总结

  • t.yield():线程t提示资源调度器,线程t愿意放弃其当前使用的处理资源。
  • 资源调度器可以忽略这个提示。
  • 当资源调度器忽略这个退让提示时,线程还是按照原来的调度进行。
  • yield()方法适用于同等优先级级别的线程之间。
  • yield()方法如果成功,则线程从Running(运行)状态切换至Runnable(就绪)状态

举例说明:

  • 程序中有两个线程:[线程A] = threadA、[线程B]=threadB,他们的优先级一样,都是默认的5。
  • 在[线程A]的run()方法中,调用了Thread.yield(),提示CPU,愿意让出CPU资源,让其他同等优先级基本的线程进行运行。
  • 可能的结果之一:CPU因为某种原因忽略了这个提示,则[线程A]继续运行。
  • 可能的结果之二:CPU认可了这个提示,并调度[线程B]来执行线程代码。

关于join()方法更形象的说法:线程退让

3.实例代码与结果

3.1.示例场景

  • 这是一个学员学习开车的场景。
  • 共有四个学员,他们拥有不同的会员级别:金卡会员DDD、银卡会员AAA、银卡会员BBB和铜卡会员CCC。
  • 他们四个学员共用一台教练车进行学车练习。
  • 由于金卡会员的优先级最高,每天学车时,DDD都是最先完成教练车的使用。
  • 金卡会员DDD在练习过程中,也想把学车机会让给其他学员。但教练不同意,因为这不符合驾校规定:优先级高的会员先练车。
  • 银卡会员AAA和BBB在练习的过程中,可以相互礼让练车机会。
  • 铜卡会员CCC,只能等其他学员都完成练习之后才能够进行练车。

3.2.代码实现

分析:线程之间的退让需要用yield()方法实现,这种退让只能发生在同样优先级级别的线程之间。

代码如下:

/**
 * <p>线程的基本方法:yield(退让)</p>
 *
 * @author hanchao 2018/3/11 16:18
 **/
public class ThreadYieldDemo {
    private static final Logger LOGGER = Logger.getLogger(ThreadYieldDemo.class);

    /**
     * <p>定义Runnable接口的实现(在驾校学车,要学会退让)</p>
     * @author hanchao 2018/3/11 16:51
     **/
    static class LearnToDriver implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                //当这个学员练习3次开车之后,尝试把机会让给同级别的学员
                if (i == 3) {
                    System.out.println(Thread.currentThread().getName() + " try to yield..");
                    Thread.currentThread().yield();
                }
                //这个学员正在练习开车
                System.out.println(Thread.currentThread().getName() + " is practicing driving....");
            }
        }
    }

    /**
     * <p>t.yield():让当前线程退让,把CPU让给其他的同样优先级级别线程</p>
     *
     * @author hanchao 2018/3/11 16:19
     **/
    public static void main(String[] args) throws InterruptedException {
        /**
         * 1.t.yield()方法针对的是running状态的线程
         * 2.t.yield()方法:t线程告诉CPU,它愿意将CPU资源让出
         * 3.调用了t.yield()并不一定100%让出资源,取决于CPU的调度情况
         * 4.t.yield()只会将资源让给同样优先级基本的线程
         */

        //定义四辆汽车
        Thread thread1 = new Thread(new LearnToDriver(), "银卡会员AAA");
        Thread thread2 = new Thread(new LearnToDriver(), "银卡会员BBB");
        Thread thread3 = new Thread(new LearnToDriver(), "铜卡会员CCC");
        Thread thread4 = new Thread(new LearnToDriver(), "金卡会员DDD");
        //设置优先级,线程1、2默认优先级为5=Thread.NORM_PRIORITY,无需修改
        thread3.setPriority(Thread.MIN_PRIORITY);
        thread4.setPriority(Thread.MAX_PRIORITY);
        //启动所有汽车
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

3.3.运行结果

由于线程退让时,CPU的具体情况多种多样,所以线程退让有两种结果:退让被忽略、退让成功。下面分别给出两种情况的执行结果。
yield(退让)被忽略:

金卡会员DDD is practicing driving....
金卡会员DDD is practicing driving....
金卡会员DDD is practicing driving....
金卡会员DDD try to yield..
金卡会员DDD is practicing driving....
金卡会员DDD is practicing driving....
银卡会员AAA is practicing driving....
银卡会员AAA is practicing driving....
银卡会员AAA is practicing driving....
银卡会员AAA try to yield..
银卡会员BBB is practicing driving....
银卡会员BBB is practicing driving....
银卡会员BBB is practicing driving....
银卡会员BBB try to yield..
银卡会员AAA is practicing driving....
银卡会员AAA is practicing driving....
银卡会员BBB is practicing driving....
银卡会员BBB is practicing driving....
铜卡会员CCC is practicing driving....
铜卡会员CCC is practicing driving....
铜卡会员CCC is practicing driving....
铜卡会员CCC try to yield..
铜卡会员CCC is practicing driving....
铜卡会员CCC is practicing driving....

结论:退让被忽略时,各线程还是各行其道。


yield(退让)成功:

金卡会员DDD is practicing driving....
金卡会员DDD is practicing driving....
金卡会员DDD is practicing driving....
金卡会员DDD try to yield..
金卡会员DDD is practicing driving....
金卡会员DDD is practicing driving....
银卡会员AAA is practicing driving....
银卡会员AAA is practicing driving....
银卡会员AAA is practicing driving....
银卡会员AAA try to yield..
银卡会员BBB is practicing driving....
银卡会员BBB is practicing driving....
银卡会员BBB is practicing driving....
银卡会员BBB try to yield..
银卡会员AAA is practicing driving....
银卡会员AAA is practicing driving....
银卡会员BBB is practicing driving....
银卡会员BBB is practicing driving....
铜卡会员CCC is practicing driving....
铜卡会员CCC is practicing driving....
铜卡会员CCC is practicing driving....
铜卡会员CCC try to yield..
铜卡会员CCC is practicing driving....
铜卡会员CCC is practicing driving....

结论:

  • 退让成功时,退让线程会由Running(运行)转为Runnable(就绪)状态。
  • 退让了的线程,与其他同优先级级别的线程一样,同样有再次获取CPU使用权的机会。