文章目录
- 多线程
- 进程和线程
- 进程
- 线程
- 继承Thread类方式实现多线程
- 设置线程名字的两个方式
- 获取正在运行的线程
- 线程调度模型和线程优先级设置
- 两种调度模型
- 优先级设置
- 线程控制
- sleep
- join
- 守护线程
- 线程生命周期
多线程
进程和线程
进程
进程:是正在运行的程序
-
是系统进行资源分配和调用的独立单位
-
每个进程都具有它自己的存储空间和系统资源
线程
线程:是进程中的单个顺序控制流,是一条执行路径
-
单线程:一个进程如果只有一条执行路径,则称之为单线程程序
-
多线程:一个进程如果有多条执行路径,则称之为多线程程序
继承Thread类方式实现多线程
-
继承 Thread 类
-
定义一个 MyThread 继承 Thread 类
-
在 MyThread 类中重写 run() 方法
-
创建 MyThread 类的对象
-
启动线程
demo:
定义一个名字为MyThread的类继承Thread类,重新里面的run方法
package com.itxs.demo01;/*** @Classname : MyThread* @Description : TODO 自定义线程 - 继承Thread类* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {@Override// 当线程被启动时,会自动调用run方法public void run() {for (int i = 0; i < 20; i++) {System.out.println("i = " + i);}}
}
创建测试类demo01
package com.itxs.demo01;/*** @Classname : demo01* @Description : TODO* @Author : lin_refuel@qq.com*/
public class demo01 {public static void main(String[] args) {// 创建线程对象MyThread mt01 = new MyThread();MyThread mt02 = new MyThread();MyThread mt03 = new MyThread();// 通过start方法来启动多线程mt01.start();mt02.start();mt03.start();}
}
运行结果:每个线程里面都是执行三次循环,并没有顺序,而是谁抢到谁执行,
设置线程名字的两个方式
- 调用方法setName()来设置线程名字
- 通过构造方法来设置线程名字
demo:
自定义的线程类
package com.itxs.demo01;/*** @Classname : MyThread* @Description : TODO 自定义线程 - 继承Thread类* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {// 无参构造public MyThread() {super();}/*** 带参数构造,设置每个线程名字* @param name 名字*/public MyThread(String name) {super(name);}@Override// 当线程被启动时,会自动调用run方法public void run() {for (int i = 0; i < 3; i++) {// this当前类,getName表示获取当前类的名字System.out.println(this.getName() + " i = " + i);}}
}
测试类demo01
package com.itxs.demo01;/*** @Classname : demo01* @Description : TODO* @Author : lin_refuel@qq.com*/
public class demo01 {public static void main(String[] args) {// 创建线程对象MyThread mt01 = new MyThread("线程01");MyThread mt02 = new MyThread("线程02");MyThread mt03 = new MyThread();// 设置每个线程的名字的方法setName();
// mt01.setName("线程01");
// mt02.setName("线程02");mt03.setName("线程03");// 通过start方法来启动多线程mt01.start();mt02.start();mt03.start();}
}
运行结果:
获取正在运行的线程
调用下面Thread类中方法,可以获取当前正在运行对象
Thread.currentThread()
main也是一个线程,设置main线程名字,没有办法通过this.getName和this.setName进行设置,只能通过上面的Thread类中方法进行设置获取
demo:
注意run方法中,输出每个线程名字的地方调用了Thread.currentThread()
package com.itxs.demo01;/*** @Classname : MyThread* @Description : TODO 自定义线程 - 继承Thread类* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {// 无参构造public MyThread() {super();}/*** 带参数构造,设置每个线程名字* @param name 名字*/public MyThread(String name) {super(name);}@Override// 当线程被启动时,会自动调用run方法public void run() {for (int i = 0; i < 3; i++) {// this当前类,getName表示获取当前类的名字// System.out.println(this.getName() + " i = " + i);System.out.println(Thread.currentThread().getName() + " i = " + i);}}
}
测试类demo01: 注意main线程获取的
package com.itxs.demo01;/*** @Classname : demo01* @Description : TODO* @Author : lin_refuel@qq.com*/
public class demo01 {public static void main(String[] args) {// 创建线程对象MyThread mt01 = new MyThread("线程01");MyThread mt02 = new MyThread("线程02");MyThread mt03 = new MyThread();// 设置每个线程的名字的方法setName();
// mt01.setName("线程01");
// mt02.setName("线程02");mt03.setName("线程03");// 通过start方法来启动多线程mt01.start();mt02.start();mt03.start();// 获取正在运行的线程对象Thread.currentThread().setName("主线程");// 设置main线程名字for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "i = " + i);}}
}
运行结果:
线程调度模型和线程优先级设置
两种调度模型
-
两种线程调度模型
-
分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间
-
抢占调度模型:优先让优先级高的线程使用 CPU,如果线程的欧优先级相同,那么随机选择一个,优先级高的线程获取的 CPU 占用时间会相对多一些
Java 使用的是抢占式的调度模型
-
优先级设置
Thread 类中设置和获取线程优先级的方法
getPriority()//返回次线程的优先级
setProiority()//更改次线程的优先级
demo:
创建一个名字为MyThread类继承Thread类
package com.itxs.demo01;/*** @Classname : MyThread* @Description : TODO 自定义线程 - 继承Thread类* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {// 无参构造public MyThread() {super();}/*** 带参数构造,设置每个线程名字* @param name 名字*/public MyThread(String name) {super(name);}@Override// 当线程被启动时,会自动调用run方法public void run() {for (int i = 0; i < 50; i++) {// this当前类,getName表示获取当前类的名字// System.out.println(this.getName() + " i = " + i);System.out.println(Thread.currentThread().getName() + " i = " + i);}}
}
测试类demo02 - 查看优先级高的线程是否能更快执行完
package com.itxs.demo01;/*** @Classname : demo02* @Description : TODO 线程优先级测试运行结果* @Author : lin_refuel@qq.com*/
public class demo02 {public static void main(String[] args) {// 创建线程MyThread mt01 = new MyThread("线程01");MyThread mt02 = new MyThread("线程02");MyThread mt03 = new MyThread("线程03");// 设置每个线程优先级mt01.setPriority(Thread.MIN_PRIORITY);// 优先级低mt02.setPriority(Thread.NORM_PRIORITY);// 优先级不变mt03.setPriority(Thread.MAX_PRIORITY); // 优先级最高// 输出每个线程优先级
// System.out.println(mt01.getPriority());//1
// System.out.println(mt02.getPriority());//5
// System.out.println(mt03.getPriority());//10// 开启线程mt01.start();mt02.start();mt03.start();}
}
运行结果: 线程mt03比其他两个线程运行快一点,仅仅一点
线程控制
sleep
sleep:使当前正在执行的线程停留指定的毫秒数
demo:案例:华山论剑
定义一个MyThread类继承Thread类
package com.itxs.demo02;/*** @Classname : MyThread* @Description : TODO* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {public MyThread() {super();}// 初始化线程名字的构造方法public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 1; i <= 20; i++) {System.out.println(Thread.currentThread().getName() + "打出了第" + i + "招");// 调用sleep使其线程执行一次循环后停留1秒try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
sleeptest测试类
package com.itxs.demo02;/*** @Classname : sleepTest* @Description : TODO sleep测试类* @Author : lin_refuel@qq.com*/
public class sleepTest {public static void main(String[] args) {// 创建线程对象MyThread mt01 = new MyThread("黄固");MyThread mt02 = new MyThread("欧阳锋");MyThread mt03 = new MyThread("段智兴");MyThread mt04 = new MyThread("洪七公");// 开启线程mt01.start();mt02.start();mt03.start();mt04.start();}
}
join
join:等待线程结束
package com.itxs.demo03;/*** @Classname : MyThread* @Description : TODO 自定义线程类 - 继承Thread类* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {public MyThread() {super();}// 设置线程名字public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName()+"报数:"+i);}}
}
test:测试类,注意join的使用,需要抛出异常
package com.itxs.demo03;/*** @Classname : test* @Description : TODO* @Author : lin_refuel@qq.com*/
public class test {public static void main(String[] args) throws InterruptedException {// 三个人报数,第一个人报完数后,其他人才能报数MyThread mt01 = new MyThread("1号");MyThread mt02 = new MyThread("2号");MyThread mt03 = new MyThread("3号");// 开始报数mt01.start();mt01.join();//等待第一个人报数完毕mt02.start();mt03.start();}
}
守护线程
setDaemon(boolean on)
将此线程标记为守护进程,当运行线程都是守护线程时,JVM 将退出
个人理解:主线程里面运行结束,守护线程不会继续执行
例子:老板带三个员工吃饭,老板吃饱后,员工不能继续吃了
demo:
定义MyThread类继承Thread类
package com.itxs.demo04;/*** @Classname : MyThread* @Description : TODO* @Author : lin_refuel@qq.com*/
public class MyThread extends Thread {public MyThread() {super();}// 设置线程对象名字public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 1; i <= 50; i++) {System.out.println(Thread.currentThread().getName() + "正在吃" + i + "口");}}
}
定义三个线程设置为守护线程,进行测试,注意守护线程设置方式
package com.itxs.demo04;/*** @Classname : test* @Description : TODO* @Author : lin_refuel@qq.com*/
public class test {public static void main(String[] args) {// 创建三个工人线程MyThread mt01 = new MyThread("1号工人");MyThread mt02 = new MyThread("1号工人");MyThread mt03 = new MyThread("1号工人");System.out.println("吃饭了");// 三个工人线程设置为守护线程,老板说吃饱了,工人就不继续吃了mt01.setDaemon(true);mt02.setDaemon(true);mt03.setDaemon(true);mt01.start();mt02.start();mt03.start();// 主线程:作为老板Thread.currentThread().setName("老板");for (int i = 1; i <5; i++) {System.out.println(Thread.currentThread().getName() + "正在吃第" + i + "口");}System.out.println("老板说吃饱了,咱们走吧");}
}
线程生命周期
-
新建:创建线程对象(通过
start()
进入下一个环节) -
就绪:有执行资格,没有执行权(抢占 CPU 的执行权)
-
运行:有执行资格,有执行权(可能被其他线程抢走 CPU 的执行权,则回到就绪状态,若遇到阻塞式方法,则失去运行权和执行这个,等待,当阻塞方法调用结束之后,回到就绪状态)
-
死亡:线程死亡,成为垃圾