线程调度

阅读:242

目录介绍

  • 01.线程执行流程
  • 02.线程调度
    • 2.1 线程的调度问题
    • 2.2 线程有两种调度模型
  • 03.线程控制
    • 3.1 sleep休眠线程
    • 3.2 join加入线程
    • 3.3 yield礼让线程
    • 3.4 setDaemon守护线程
    • 3.5 stop中断线程
    • 3.6 start开启线程

01.线程执行流程

1.jpeg

02.线程调度

2.1 线程的调度问题

  • 应用程序在执行的时候都需要依赖于线程去抢占CPU的时间片 , 谁抢占到了CPU的时间片,那么CPU就会执行谁
  • 线程的执行:假如我们的计算机只有一个 CPU,那么 CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。

2.2 线程有两种调度模型

  • 分时调度模型
    • 所有线程轮流使用CPU的使用权,平均分配每个线程占用 CPU 的时间片
  • 抢占式调度模型
    • 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。Java使用的是抢占式调度模型。

03.线程控制

3.1 线程控制之休眠线程

  • sleep方法
    • public static void sleep(long time) ;
    • time表达的意思是休眠的时间 , 单位是毫秒
  • sleep方法具体作用
    • 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
    • 让其他线程有机会继续执行,但它并不释放对象锁。也就是如果有Synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常。
  • sleep如何使低优先级线程执行
    • 比如有两个线程同时执行(没有Synchronized),一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。
    • 总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。
  • 怎么唤醒一个阻塞的线程?
    • 如果线程是因为调用了wait()、sleep()或者join()方法而导致的阻塞,可以中断线程,并且通过抛出InterruptedException来唤醒它;如果线程遇到了IO阻塞,无能为力,因为IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。
  • Thread.sleep(0)的作用是啥?
    • 由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况,为了让某些优先级比较低的线程也能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。

3.2 线程控制之加入线程

  • join方法
    • public final void join()
    • 等待该线程执行完毕了以后,其他线程才能再次执行。Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。
    • 保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。
  • join()有什么作用?
    • Thread的join()的含义是等待该线程终止,即将挂起调用线程的执行,直到被调用的对象完成它的执行。比如存在两个线程t1和t2,下述代码表示先启动t1,直到t1的任务结束,才轮到t2启动。
    t1.start();
    t1.join(); 
    t2.start();
    

  • 注意事项:
    • 在线程启动之后,才能调用调用方法。如果没有启动,调用该方法,则直接会……

3.3 线程控制之礼让线程

  • yield方法
    • public static void yield():
    • 暂停当前正在执行的线程对象,并执行其他线程。
  • 线程礼让的原理是:
    • 暂定当前的线程,然CPU去执行其他的线程,这个暂定的时间是相当短暂的;当我某一个线程暂定完毕以后,其他的线程还没有抢占到cpu的执行权 ;那么这个是时候当前的线程会和其他的线程再次抢占cpu的执行权;
  • yield礼让线程会释放锁吗
    • yield()方法和sleep()方法类似,也不会释放“锁标志”,区别在于,它没有参数,即yield()方法只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行,另外yield()方法只能使同优先级或者高优先级的线程得到执行机会,这也和sleep()方法不同。

3.4 线程控制之守护线程

  • setDaemon方法
    • public final void setDaemon(boolean on)
    • 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 -
  • 注意要点:
    • 该方法必须在启动线程前调用。
    • jvm会线程程序中存在的线程类型,如果线程全部是守护线程,那么jvm就停止。

3.5 线程控制之中断线程

  • stop方法
    • public final void stop():
    • 停止线程的运行
  • interrupt方法
    • public void interrupt():
    • 中断线程(这个翻译不太好),查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞

3.6 start开启线程

  • 多次start会怎么样
    • 将会抛出java.lang.IllegalThreadStateException,也就是线程状态非法异常
    • 下面代码大概意思是:首先校验状态,如果不是新建状态或者已经创建过则直接抛出异常。然后将当前线程添加进线程组,然后调用原生run方法并且记录开启状态started为true,当然如果线程启动失败,从线程组中移除当前前程。
    public synchronized void start() {
        if (threadStatus != 0 || started)
            throw new IllegalThreadStateException();
        group.add(this);
        started = false;
        try {
            nativeCreate(this, stackSize, daemon);
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

赞赏支持


精彩留言

发表评论