Java多线程学习系列(三)之线程调度

线程调度

前言

  计算机通常只有一个CPU。所谓多线程的并发运行,其实是指宏观上看各个线程轮流获得CPU的使用权。Java虚拟机就是负责线程的调度

一、 两种调度模型

1.1 分时调度模型

  指让所有线程轮流获得CPU的使用权,并且平均分配每个线程占用CPU的时间。

1.2 抢占调度(JAVA虚拟机采用的调度模式)

  指优先让可以运行池中优先级高的线程占用CPU,如果可运行线程池中的优先级相同,那么就随机地选择一个线程,使其占用CPU。处于运行状态的线程会一直运行,直至它不得不放弃CPU。

1.3 、线程放弃CPU的原因

  1. Java虚拟机让当前线程暂时放弃CPU ,转到就绪状态,使其他线程获得运行机会。
  2. 当前线程因为某些原因进入阻塞状态
  3. 线程运行结束

Tips

1.线程的调度不是跨平台的,它不仅仅取决于Java寻虚拟机,还依赖于操作系统。
2.Java线程的调度不是分时的,同时启动多个线程后不能保证各个线程轮流获得均等的CPU时间片

二 、Java明确让一个线程给另外一个线程运行机会采用的方法

  1. 调整各个线程的优先级
  2. 让处于运行的线程调用Thread.sleep()方法
  3. 让处于运行状态的线程调用Thread.yueld()方法
  4. 让处于运行状态的线程调用另一个线程的join()方法

2.1 调整各个线程的优先级

  所有处于就绪状态的线程根据优先级存放在可运行池中,优先级低的线程获得较少的运行机会。
  Thread类的**setPriority(int i)和 getPriority()**方法分别来设置优先级和读取优先级。取值范围1~10,Thread常用三个静态变量(建议调整线程优先级时适用默认值)

  1. MAX_PRIORITY: 取值为10,表示最高优先级
  2. MIN_PRIORITY:取值为1,表示最低优先级
  3. NORM_PRIORITY:取值为5,表示默认优先级

注意:

  1. 每个线程都有默认的优先级,主线程的默认优先级为Thread.NORM_PRIORITY。如果线程A创建了线程B,那么B将和A具有同样的优先级。
  2. 尽管java提供了10个优先级,但是它与多数操作系统都不能很好的进行线程优先级的映射。比如Window有7个优先级,并不是固定的。而Solaris操作系统有2^31个优先级。如果希望程序能够移植到各个操作系统中,因该确保在设置线程的优先级时,只使用MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY这三个默认优先级。

2.2、线程睡眠: Thread.sleep()方法

  当一个线程执行了sleep()方法,就会放弃CPU,转到阻塞状态。sleep(Long millis)参数设定睡眠时间,单位:毫秒。当线程睡眠结束,首先转到就绪状态

public class Sleeper extends Thread {
    @Override
    public void run() {
        try {
            sleep(60000);
            System.out.println("sleep over");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end");
    }

    public static void main(String[] args) throws InterruptedException {
        Sleeper sleeper = new Sleeper();
        sleeper.start();
        Thread.sleep(10);
        sleeper.interrupt();// 终端睡眠
    }
}

2.3、线程让步:Thread.yield()方法

  当前线程执行yield()静态方法时,如果此时具有相同优先级的其他线程处于就绪状态,yield()方法将当前运行的线程放到可运行池中并使另一个线程运行。如果没有相同优先级的可运行进程,yield()方法什么都不做。

2.4、sleep()和yield()区别

  • sleep()方法会给其他线程运行的机会,不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行机会。
  • 当线程执行了sleep(Long millis)方法后,将转到阻塞状态,参数millis指定睡眠时间,当线程执行额yield()方法以后,将转到就绪状态
  • sleep()方法生命抛出InterruptddException异常,yield()方法不抛出异常
  • sleep()方法比yield()方法具有更好的可移植性。不能依靠yield()方法来提高程序的并发性能。实际开发中几乎不适用yield()方法提高并发性能.

2.5、等待其他线程结束:join()

  当前运行的线程可以调用另一个线程的join()方法。当前运行的线程转到阻塞状态,直至另一个线程运行结束,他才回复运行

2.5.1、 join()方法的两种重载形式

public void join()
public void join(Long timeOut)

timeout参数设定当前线程被阻塞的时间,单位:毫秒

machine.join(10)

当主线程被阻塞的时间超过10毫秒,或者machine线程运行结束时,主线程就恢复运行


public class Machine extends Thread {
    @Override
    public void run() {
        for (int a = 0; a < 200; a++) {
            System.out.println(getName() + ":" + a);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Machine machine = new Machine ();
        machine .setName("t1");
        machine .start();
        System.out.println("main:join machine");
        machine .join(10);
        System.out.println("main:end");// 主线程运行结束
    }
}

打印结果(可能出现的情况):

main:join machine
t1:0
t1:1
t1:2
……
t1:55
main:end
t1:56
……

注:学习内容和代码,来源自《JAVA 面向对象编程》(第二版)作者:孙卫琴

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值