一、基础概念
1、线程调度
某个线程若想被执行,必须得到CPU的使用权,
java虚拟机会按照特定的机制为程序中的每个线程分配CPU的使用权,这种机制被称为线程的调度
线程调度有两种模型:分时调度 和 抢占式调度
2、分时调度
让所有的线程轮流获得CPU的使用权,并且平均分配每个线程占用的CPU的时间片
3、抢占式调度
让可运行池中优先级高的线程优先占用CPU,而对于优先级相同的线程,随机选择一个线程使其占用CPU,
java虚拟机默认采用抢占式调度模型
二、线程的优先级
1、在应用程序中,如果要对线程进行调度,最直接的方式就是设置线程的优先级,
线程的优先级用1~10之间的整数来表示,10最高
除了可以直接用数字,还可以使用Thread类中提供的三个静态常量来表示线程的优先级
2、程序在运行期间,处于就绪状态的每个线程都有自己的优先级,例如main线程具有普通优先级
可以通过Thread类的setPriority(int newPriority)方法对其进行设置,
package cn.itcast.chapter10.example06;
/**
* 不同优先级的两个线程在程序中运行情况
*/
public class Example06 {
public static void main(String[] args) {
//创建两个线程
Thread minPriority = new Thread(new Task(), "优先级较低的线程 ");
Thread maxPriority = new Thread(new Task(), "优先级较高的线程 ");
minPriority.setPriority(Thread.MIN_PRIORITY); //设置线程的优先级为1
maxPriority.setPriority(Thread.MAX_PRIORITY); //设置线程的优先级为10
//开启两个线程
minPriority.start();
maxPriority.start();
}
}
//定义一个线程的任务类
class Task implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在输出" + i);
}
}
}
输出
优先级较高的线程 正在输出0
优先级较高的线程 正在输出1
优先级较高的线程 正在输出2
优先级较高的线程 正在输出3
优先级较高的线程 正在输出4
优先级较高的线程 正在输出5
优先级较高的线程 正在输出6
优先级较高的线程 正在输出7
优先级较高的线程 正在输出8
优先级较高的线程 正在输出9
优先级较低的线程 正在输出0
优先级较低的线程 正在输出1
优先级较低的线程 正在输出2
优先级较低的线程 正在输出3
优先级较低的线程 正在输出4
优先级较低的线程 正在输出5
优先级较低的线程 正在输出6
优先级较低的线程 正在输出7
优先级较低的线程 正在输出8
优先级较低的线程 正在输出9
三、线程休眠
当前线程调用sleep(long millis) 之后,指定时间(参数millis)之内线程是不会执行的
sleep(long millis)方法会抛出InterrupedException
main主函数为了代码整洁,使用 thr ows Exception
任务类中使用 try...catch
package cn.itcast.chapter10.example07;
/**
* sleep(long millis) 方法在程序中的使用
*/
public class Example07 {
public static void main(String[] args) throws InterruptedException {
//创建一个线程
new Thread(new Task()).start();
for (int i = 1; i <= 10; i++) {
if (i == 5) {
Thread.sleep(2000); //当前main主线程 休眠2秒
} else {
Thread.sleep(500);
}
System.out.println("main主线程正在输出:" + i);
}
}
}
//定义线程的任务类
class Task implements Runnable {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
try{
if (i == 3) {
Thread.sleep(2000);//当前线程休眠2秒
} else {
Thread.sleep(500);
}
System.out.println("线程一正在输出:" + i);
} catch (Exception e){
e.printStackTrace();
}
}
}
}
输出
main主线程正在输出:1
线程一正在输出:1
main主线程正在输出:2
线程一正在输出:2
main主线程正在输出:3
main主线程正在输出:4
线程一正在输出:3
线程一正在输出:4
main主线程正在输出:5
线程一正在输出:5
main主线程正在输出:6
线程一正在输出:6
main主线程正在输出:7
线程一正在输出:7
main主线程正在输出:8
线程一正在输出:8
main主线程正在输出:9
线程一正在输出:9
main主线程正在输出:10
线程一正在输出:10
四、线程让步
线程让步是通过yield() 方法实现,
和sleep()方法不同,yield()不会让线程阻塞,只是将线程转换成就绪状态,让系统的调度器重新调度一次,
package cn.itcast.chapter10.example08;
/**
* 线程让步,yield()方法的使用
*/
public class Example08 {
public static void main(String[] args) {
// 创建两个线程
Thread t1 = new YieldThread("线程A");
Thread t2 = new YieldThread("线程B");
// 开启两个线程
t1.start();
t2.start();
}
}
// 定义YieldThread类继承Thread类
class YieldThread extends Thread {
// 定义一个有参的构造方法
public YieldThread(String name) {
super(name); // 调用父类的构造方法
}
public void run() {
for (int i = 0; i < 6; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
if (i == 3) {
System.out.println("线程让步:");
Thread.yield(); // 线程运行到此,作出让步
}
}
}
}
输出
线程A---0
线程A---1
线程A---2
线程A---3
线程让步:
线程B---0
线程B---1
线程B---2
线程B---3
线程让步:
线程A---4
线程A---5
线程B---4
线程B---5
五、线程插队
当在某个线程中调用其他线程的 join() 方法时,调用的线程将被阻塞,知道被join()方法加入的线程执行完毕它才会继续进行,
package cn.itcast.example09;
/**
* @author wangyue
* @version 1.0
* @date 2019/7/9 9:54
* @describe:线程插队,join()方法的使用
*/
public class Example09{
public static void main(String[] args) throws Exception {
// 创建线程
Thread t = new Thread(new EmergencyThread(),"线程一");
t.start(); // 开启线程
System.out.println("t.start()之后");
for (int i = 1; i < 6; i++) {
System.out.println(Thread.currentThread().getName()+"输出:"+i);
if (i == 2) {
System.out.println("调用t.join();");
t.join(); // 调用join()方法
}
Thread.sleep(500); // 线程休眠500毫秒
}
}
}
class EmergencyThread implements Runnable {
public void run() {
System.out.println("进入线程类");
for (int i = 1; i < 6; i++) {
System.out.println(Thread.currentThread().getName()+"输出:"+i);
try {
Thread.sleep(500); // 线程休眠500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出
t.start()之后
main输出:1
进入线程类
线程一输出:1
main输出:2
调用t.join();
线程一输出:2
线程一输出:3
线程一输出:4
线程一输出:5
main输出:3
main输出:4
main输出:5
如果线程任务类不sleep,则会一直执行完毕
package cn.itcast.example09;
/**
* @author wangyue
* @version 1.0
* @date 2019/7/9 9:54
* @describe:线程插队,join()方法的使用
*/
public class Example09{
public static void main(String[] args) throws Exception {
// 创建线程
Thread t = new Thread(new EmergencyThread(),"线程一");
t.start(); // 开启线程
System.out.println("线程t的优先级:"+t.getPriority());
System.out.println("main的优先级数:"+Thread.currentThread().getPriority());
System.out.println("\nt.start()之后");
for (int i = 1; i < 6; i++) {
System.out.println(Thread.currentThread().getName()+"输出:"+i);
if (i == 2) {
System.out.println("调用t.join();");
System.out.println();
t.join(); // 调用join()方法
}
Thread.sleep(500); // 线程休眠500毫秒
}
}
}
class EmergencyThread implements Runnable {
public void run() {
System.out.println("进入线程类");
for (int i = 1; i < 6; i++) {
System.out.println(Thread.currentThread().getName()+"输出:"+i);
/*try {
Thread.sleep(500); // 线程休眠500毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
}
}
输出
线程t的优先级:5
main的优先级数:5
t.start()之后
main输出:1
进入线程类
线程一输出:1
线程一输出:2
线程一输出:3
线程一输出:4
线程一输出:5
main输出:2
调用t.join();
main输出:3
main输出:4
main输出:5