本章目标
- 进程与线程的区别
- 创建线程方法
- 线程调度
- 线程控制
1.进程和线程
进程:是正在运行的程序(了解)
- 是系统进行资源分配和调用的独立单位
- 每一个进程都有它自己的内存空间和系统资源
线程:是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个进程如果只有一条执行路径,则称为单线程程序
- 多线程:一个进程如果有多条执行路径,则称为多线程程序
2.实现多线程方式一:继承Thread
方法介绍:
方法名 | 说明 |
---|---|
void run() | 在线程开启后,此方法将被调用执行 |
void start() | 使此线程开始执行,Java虚拟机会调用run方法() |
实现步骤
- 定义一个类MyThread继承Thread类
- 在MyThread类中重写run()方法
- 创建MyThread类的对象
- 启动线程start()
代码演示:
/*
定义线程类
*/
public class MyThread extends Thread{
//重写run方法
@Override
public void run() {
//线程处理的工作
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
//获取线程的实例
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
//启动线程,run()不能启动线程
// mt1.run();
// mt2.run();
mt1.start();
mt2.start();
}
}
小结:
为什么要重写run()方法?
- 因为run()是用来封装被线程执行的代码
run()方法和start()方法的区别?
- run():封装线程执行的代码,直接调用,相当于普通方法的调用
- start():启动线程;然后由JVM调用此线程的run()方法
3.设置和获取线程名称
方法介绍
方法名 | 说明 |
---|---|
void setName(String name) | 将此线程的名称更改为等于参数name |
String getName() | 返回此线程的名称 |
Thread currentThread() | 返回对当前正在执行的线程对象的引用 |
代码演示
/*
定义线程类
*/
public class MyThread extends Thread{
//重写run方法
@Override
public void run() {
//线程处理的工作
for(int i=0;i<100;i++){
System.out.println(getName()+":"+i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
//获取线程的实例
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
//命名
mt1.setName("飞机");
mt2.setName("高铁");
//启动线程,run()不能启动线程
// mt1.run();
// mt2.run();
mt1.start();
mt2.start();
//获取主线程名字
Thread.currentThread().setName("zhuxiancheng");
System.out.println(Thread.currentThread().getName());
}
}
4.线程调度
线程调度概述
两种调度方式
- 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
- 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些
Java使用的是抢占式调度模型
随机性
- 假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的
相关方法
方法名 | 说明 |
---|---|
final int getPriority() | 返回此线程的优先级 |
final void setPriority(int newPriority) | 更改此线程的优先级 线程默认优先级是5;线程优先级的范围是:1-10 |
代码演示(飞机、高铁、汽车)
public class JiaoTongThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(getName()+":"+i);
}
}
}
/*
线程调度
setPriority(int newPriority)更改线程的优先级。
getPriority() 返回线程的优先级。
*/
public class Demo2 {
public static void main(String[] args) {
//创建线程
JiaoTongThread jt1 = new JiaoTongThread();
JiaoTongThread jt2 = new JiaoTongThread();
JiaoTongThread jt3 = new JiaoTongThread();
//命名
jt1.setName("火箭");
jt2.setName("飞机");
jt3.setName("船");
// System.out.println(Thread.MAX_PRIORITY);//10
// System.out.println(Thread.MIN_PRIORITY);//1
// System.out.println(Thread.NORM_PRIORITY);//5
// System.out.println(jt1.getPriority());
//设置优先级
jt1.setPriority(1);//IllegalArgumentException参数不合法
jt3.setPriority(10);
//启动
jt1.start();
jt2.start();
jt3.start();
}
}
5.线程控制
相关方法:
方法名 | 说明 |
---|---|
static void sleep(long millis) | 使当前正在执行的线程停留(暂停执行)指定的毫秒数 |
void join() | 等待这个线程死亡 |
void setDaemon(boolean on) | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 |
代码演示:
Sleep演示:曹操、刘备、孙权
public class SleepThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
try {
sleep(100);//休眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+":"+i);
}
}
}
public class Demo {
public static void main(String[] args) {
//创建线程
SleepThread st1 = new SleepThread();
SleepThread st2 = new SleepThread();
//命名
st1.setName("火箭");
st2.setName("飞机");
//启动
st1.start();
st2.start();
}
}
Join演示:康熙、四阿哥、八阿哥
public class JoinThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
try {
sleep(10);//休眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+":"+i);
}
}
}
/*
join();等待这个线程死亡
*/
public class Demo {
public static void main(String[] args) throws InterruptedException {
//康熙、四阿哥、八阿哥
JoinThread jt1 = new JoinThread();
JoinThread jt2 = new JoinThread();
JoinThread jt3 = new JoinThread();
//命名
jt1.setName("康熙");
jt2.setName("四阿哥");
jt3.setName("八阿哥");
//启动
jt1.start();
jt1.join();
jt2.start();
jt3.start();
}
}
Daemon演示:刘备、关羽、张飞
public class DaemonThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
try {
sleep(10);//休眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+":"+i);
}
}
}
/*
void setDaemon(boolean on)
将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
*/
public class Demo {
public static void main(String[] args) throws InterruptedException {
DaemonThread dt1 = new DaemonThread();
DaemonThread dt2 = new DaemonThread();
//命名
dt1.setName("关羽");
dt2.setName("张飞");
//设置(当前)主线程名称
Thread.currentThread().setName("刘备");
//设置守护线程
dt1.setDaemon(true);
dt2.setDaemon(true);
//start
dt1.start();
dt2.start();
for(int i=0;i<10;i++){
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
6.线程生命周期
7.多线程实现方式二:实现Runnable接口
Thread构造方法
方法名 | 说明 |
---|---|
Thread(Runnable target) | 分配一个新的Thread对象 |
Thread(Runnable target, String name) | 分配一个新的Thread对象 |
实现步骤
- 定义一个类MyRunnable实现Runnable接口
- 在MyRunnable类中重写run()方法
- 创建MyRunnable类的对象
- 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
- 启动线程
代码演示:
/*
实现Runnable接口实现线程
*/
public class RunnableThread implements Runnable{
@Override
public void run() {
//线程代码
for(int i=0;i<100;i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Thread.currentThread() 获取当前线程实例
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class Demo {
public static void main(String[] args) {
// 创建线程
RunnableThread runnableThread = new RunnableThread();
Thread thread1 = new Thread(runnableThread,"飞机");
Thread thread2 = new Thread(runnableThread,"高铁");
//启动线程
thread1.start();
thread2.start();
}
}
小结
多线程的实现方案有两种
- 继承Thread类
- 实现Runnable接口
相比继承Thread类,实现Runnable接口的好处
- 避免了Java单继承的局限性
- 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想