1.4 线程的调度与控制

线程的调度与控制

通常我们的计算机只有一个 CPU,CPU 在某一个时刻只能执行一条指令,线程只有得到 CPU

时间片,也就是使用权,才可以执行指令。在单 CPU 的机器上线程不是并行运行的,只有在

多个 CPU 上线程才可以并行运行。Java 虚拟机要负责线程的调度,取得 CPU的使用权,目前

有两种调度模型:分时调度模型和抢占式调度模型,Java 使用抢占式调度模型。

分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

抢占式调度模型:优先级高的线程获取 CPU 的时间片相对多一些,如果线程的优先级相同,那么会随机选择一个。

线程优先级

线 程 优 先 级 主 要 分 三 种 : MAX_PRIORITY( 最高级 );MIN_PRIORITY (最低级);NOM_PRIORITY(标准)默认

public class Demo {
    public static void main(String[] args) {
        Runnable r1 = new Processor();
        Thread t1 = new Thread(r1, "t1");
        //设置线程的优先级,线程启动后不能再次设置优先级
        //必须在启动前设置优先级
        //设置最高优先级
        t1.setPriority(Thread.MAX_PRIORITY);
        //启动线程
        t1.start();

        Thread t2 = new Thread(r1, "t2");
        //设置最低优先级
        t2.setPriority(Thread.MIN_PRIORITY);
        t2.start();

        System.out.println(Thread.currentThread().getName());
    }
}
     class Processor implements Runnable {
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "," + i);
            }
        }
    }

在这里插入图片描述

从以上输出结果应该看可以看出,优先级高的线程(t1)会得到的 CPU 时间多一些,优先执行完成。

Thread.sleep

sleep 设置休眠的时间,单位毫秒,当一个线程遇到 sleep 的时候,就会睡眠,进入到阻塞状态,放弃 CPU,腾出 cpu 时间片,给其他线程用,所以在开发中通常我们会这样做,使其他的线程能够取得 CPU 时间片,当睡眠时间到达了,线程会进入可运行状态,得到 CPU 时间片继续执行,如果线程在睡眠状态被中断了,将会抛出IterruptedException异常。

【示例代码】

public class Demo {
    public static void main(String[] args) {
        Runnable r1 = new Processor();
        Thread t1 = new Thread(r1, "t1");
        t1.start();
        Thread t2 = new Thread(r1, "t2");
        t2.start();
    }
}
class Processor implements Runnable {
    public void run() {
        for (int i=0; i<100; i++) {
            System.out.println(Thread.currentThread().getName() + "," + i);
            if (i % 10 == 0) {
                try {
//睡眠 100 毫秒,主要是放弃 CPU 的使用,将 CPU 时间片交给其他线程使用
                    Thread.sleep(100);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Thread.yield

它与 sleep()类似,只是不能由用户指定暂停多长时间,并且 yield()方法只能让同优先级的线程有执行的机会

public class Demo {
    public static void main(String[] args) {
        Runnable r1 = new Processor();
        Thread t1 = new Thread(r1, "t1");
        t1.start();
        Thread t2 = new Thread(r1, "t2");
        t2.start();
    }
}
class Processor implements Runnable {
    public void run() {
        for (int i=0; i<100; i++) {
            System.out.println(Thread.currentThread().getName() + "," + i);
            if (i % 10 == 0) {
                System.out.println("--------------");
//采用 yieid 可以将 CPU 的使用权让给同一个优先级的线程
                Thread.yield();
            }
        }
    }
}

interrupt(中断)

如果我们的线程正在睡眠,可以采用 interrupt 进行中断

public class Demo {
    public static void main(String[] args) {
        Runnable r1 = new Processor();
        Thread t1 = new Thread(r1, "t1");
        t1.start();
        try {
        //设置为 500 毫秒,没有出现中断异常,因为
        //500 毫秒之后再次调用 t1.interrupt()时,
        //此时的睡眠线程已经执行完成
        //如果 sleep 的时间设置的小一些,会出现中断异常,
        //因为存在睡眠线程
            Thread.sleep(500);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //中断睡眠中的线程
        t1.interrupt();
    }
}
    class Processor implements Runnable {
        public void run() {
            for (int i = 1; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "," + i);
                if (i % 50 == 0) {
                    try {
                        Thread.sleep(200);
                    } catch (Exception e) {
                        System.out.println("-------中断-------");
                        break;
                    }
                }
            }
        }
    }

守护线程

从线程分类上可以分为:用户线程(以上讲的都是用户线程),另一个是守护线程。守护线程是这样的,所有的用户线程结束生命周期,守护线程才会结束生命周期,只要有一个用户线程存在,那么守护线程就不会结束,例如 java 中著名的垃圾回收器就是一个守护线程,只有应用程序中所有的线程结束,它才会结束。

public class Demo {
    public static void main(String[] args) {
        Runnable r1 = new Processor();
        Thread t1 = new Thread(r1, "t1");
        t1.start();
        for (int i=0; i<10; i++) {
        System.out.println(Thread.currentThread().getName() + ", " + i);
        	}
        System.out.println("主线程结束!!!");
     }
}
    class Processor implements Runnable {
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ", " + i);
            }
        }
    }

在这里插入图片描述

以上可以看出,主线程执行结束了,但用户线程仍然将数据打印出来了

修改为守护(服务线程)线程, thread.setDaemon(true)

public class Demo {
    public static void main(String[] args) {
        Runnable r1 = new Processor();
        Thread t1 = new Thread(r1, "t1");
    //将当前线程修改为守护线程
    //在线程没有启动时可以修改以下参数

        for (int i=0; i<10; i++) {
            System.out.println(Thread.currentThread().getName() + ", " + i);
        }
        System.out.println("主线程结束!!!");
        t1.setDaemon(true);
        t1.start();
    }

}
    class Processor implements Runnable {
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ", " + i);
            }
        }
    }

设置为守护线程后,当主线程结束后,守护线程并没有把所有的数据输出完就结束了,也即是说守护线程是为用户线程服务的,当用户线程全部结束,守护线程会自动结束。

thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个lllegalThreadStateException异常。不能把正在运行的常规线程设置为守护线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值