多线程相关的概念
- 并发与并行
并行:在同一时刻,有多个任务在多个CPU上同时执行。
并发:在同一时刻,有多个任务在单个CPU上交替执行。
- 进程与线程
进程:就是操作系统中正在运行的一个应用程序。
线程:就是应用程序中做的事情。比如:360软件中的杀毒,扫描木马,清理垃圾。
什么是多线程
- 是指从软件或者硬件上实现多个线程并发执行的技术。
具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。
- 好处 : 提高任务的执行性能
多线程的创建方式
继承Thread方式
基本步骤:
- 创建一个类继承 Thread 类。
- 在类中重写run方法(线程执行的任务放在这里)
- 创建线程对象,调用线程的start方法开启线程。
- 执行程序,观察控制台的打印数据的现象
/* 线程的创建方式1:继承Thread方式 基本步骤 : 1 创建一个类继承Thread类。 2 在类中重写run方法(线程执行的任务放在这里) 3 创建线程对象,调用线程的start方法开启线程。 需求 : 我们启动一个Java程序,其实默认就存在一个主线程(main方法所在线程) 接下来,我们在主线程启动一个线程,打印1到100的数字,主线程启动完线程后又打印1到100的数字。 此时主线程和启动的线程在并发执行,观察控制台打印的结果。 */ public class MyThread01 { public static void main(String[] args) { // 创建线程对象,调用线程的start方法开启线程。 MyThread mt = new MyThread(); mt.start(); // main方法中的任务 for (int i = 1; i <= 100; i++) { System.out.println("i:" + i); } } } // 创建一个类继承Thread类。 class MyThread extends Thread { // 在类中重写run方法(线程执行的任务放在这里) @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("i:" + i); } } }
实现Runable方式
- 构造方法
public Thread(Runnable target)
public Thread(Runnalbe target , String name)
- 实现步骤
定义任务类实现Runnable,并重写run方法
创建任务对象
使用含有Runnable参数的构造方法,创建线程对象并指定任务。
调用线程的start方法,开启线程
/* 线程的创建方式2:实现Runnable方式 基本步骤 : 1 定义任务类实现Runnable,并重写run方法 2 创建任务对象 3 使用含有Runnable参数的构造方法,创建线程对象并指定任务。 4 调用线程的start方法,开启线程 需求 : 我们启动一个Java程序,其实默认就存在一个主线程(main方法所在线程) 接下来,我们在主线程启动一个线程,打印1到100的数字,主线程启动完线程后又打印1到100的数字。 此时主线程和启动的线程在并发执行,观察控制台打印的结果。 */ public class MyThread02 { public static void main(String[] args) { // 创建线程对象,调用线程的start方法开启线程。 MyRunnable mr = new MyRunnable(); Thread thread= new Thread(mr); thread.start(); // main方法中的任务 for (int i = 1; i <= 100; i++) { System.out.println("i:" + i); } } } // 1 定义任务类实现Runnable,并重写run方法 class MyRunnable implements Runnable { // 在类中重写run方法(线程执行的任务放在这里) @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("i:" + i); } } }
两种方式比较
实现方式 | 优点 | 缺点 |
实现 Runnable | 扩展性强 实现接口的同时还可以继承其他的类 |
编程相对复杂 不能直接使用Thread中的方法 |
继承 Thread | 编程比较简单 可以直接使用Thread中的方法 |
可扩展性差 不能再继承其他的类 |
Thread类中常用方法
- String getName():返回此线程的名称
- Thread类中设置线程的名字
void setName(String name):将此线程的名称更改为等于参数 name
通过构造方法也可以设置线程名称
- public static Thread currentThread():返回对当前正在执行的线程对象的引用
- public static void sleep(long time):让线程休眠指定的时间,单位为毫秒
- public final synchronized void join(long millis):
当在使用多线程编程时,可能会创建多个线程来同时执行不同的任务。join 方法是一个用来管理线程执行顺序的重要工具。
当一个线程调用另一个线程的 join 方法时,它会等待被调用线程执行完成,然后再继续执行。换句话说,调用了 join
方法的线程会在被调用线程完成后才会结束。
这对于需要确保某些线程在其他线程执行完毕后再执行的情况非常有用。例如,如果你有一个主线程和两个子线程,主线程需要等待两个子线程都完成后再做某些处理,你就可以在主线程中调用两个子线程的
join 方法,这样主线程就会等待两个子线程都执行完毕后再继续执行。
需要注意的是,如果你不使用 join 方法,主线程和子线程可能会同时执行,这可能会导致竞争条件或其他问题。所以,在多线程编程中,合理地使用 join
方法可以确保线程的执行顺序和逻辑正确性。
- 线程有两种调度模型
分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些
/* 线程有两种调度模型 1 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片 2 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程 获取的 CPU 时间片相对多一些 注意 : Java使用的是抢占式调度模型 优先级高 , 只是抢夺到cpu执行的概率高而已 , 只是一种概率问题 */ public class PriorityDemo { public static void main(String[] args) { Thread thread1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } }); // 优先级最低 thread1.setPriority(1); thread1.start(); Thread thread2 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } }); // 优先级最高 thread2.setPriority(10); thread2.start(); } }