
🚗🚗🚗🚗🚗🚗🚗 数据结构专栏🚗🚗🚗🚗🚗🚗🚗🚗🚗🚗
🛹🛹🛹🛹🛹🛹🛹小知识总结分享🛹🛹🛹🛹🛹🛹🛹🛹🛹🛹
🚀🚀🚀🚀🚀🚀🚀题目历练场🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀
🚢🚢🚢🚢🚢🚢🚢功能包与集合类介绍🚢🚢🚢🚢🚢🚢🚢🚢🚢
🛞🛞🛞🛞🛞🛞🛞java EE🛞🛞🛞🛞🛞🛞🛞🛞🛞🛞🛞🛞🛞
文章目录
- [一、 线程的理解](#一、 线程的理解)
- [二、 Thread类](#二、 Thread类)
- [三、 第一个多线程程序](#三、 第一个多线程程序)
-
- 方法1,继承thread类
- 方法2,实现Runnable接口
-
- runnable接口
- [Runnable 和 Thread 的关系](#Runnable 和 Thread 的关系)
- 方法三、匿名内部类创建Thread子类对象
- 方法四、匿名内部类创建Runnable子类对象
- 方法五、lambda表达式创建Runnable子类对象(最推荐的),本质上与4相同.
- 线程的管理
- 总结
大家好耶,今天书接上回,了解了计算机是怎么工作的后,这篇文章就来说说啥是线程,thread的常见方法,手动创建一个线程~ 打开线程是怎么在java中创建的.话不多说~ 让我们开始吧~
一、 线程的理解
可以理解线程就是一个"执行流 ",每个线程中都是一系列的代码逻辑,每个线程与线程都会按照顺序执行自己的代码.
- 为什么要引入这个线程呢~
解决并发问题
- 之前大都是单核的,可是随着时代进步.多线程是不可避免的.举一个例子,之前手机只能单个运行一个APP,现在可能多个执行,比如手机的小窗模式~
线程编程的优势
- 提高程序并发性:线程允许程序同时执行多个任务,例如在图形界面程序中,一个线程处理用户输入,另一个线程执行后台计算。
- 资源开销低:线程共享进程资源(如内存、文件句柄),创建和切换的开销远小于进程。
- 简化复杂任务:多线程可将任务拆分为并行执行的子任务,如Web服务器同时处理多个客户端请求。
- 利用多核性能:多线程程序能有效利用多核CPU的并行计算能力,加速任务完成。
线程与进程的联系
还有一个名词就是进程,其实线程是进程的子集.
- 每个进程至少存在一个线程,就是主线程~
- 进程与进程之间不共享内存空间~,但是在同一个进程的多个线程之间会资源共享,下买是图就会好理解.
- 注意,虽然感觉进程比较大,但是进程是系统分配资源的最小单位.
- 线程是系统调度的最小单位.
- 一个进程挂了一般不会影响其他进程,但是一个进程中的线程挂了,可能会影响这个进程中的其他线程.

二、 Thread类
thread类是java中用来创建与控制线程的
- 是 java.lang.Thread
- 用来 创建和控制线程,实现多线程
- 有两种常用写法:
- 继承 Thread 类
- 实现 Runnable 接口
常用构造方法
java
Thread()
Thread(String name)
Thread(Runnable target)
Thread(Runnable target, String name)

常用方法

-
id是线程的唯一标识,不同线程不会重复
-
状态表示线程当前所处的情况
-
前台线程 默认创建的线程都是前台线程~
-
后台线程:前台线程全死 → 它跟着死
- 怎么使用呢~,就是通过我们类继承或者实现接口,这是总的大方向,下面呢我会距离5种常见的线程实现方式
注.start .join等方法,会在下面的实例中在做解释~
三、 第一个多线程程序
下面呢,咱们就通过java搞一个多线程的程序.进一步认识线程是如何创建的,理解其中的方法.
方法1,继承thread类
java
//第一个多线程程序
//1创建子类,继承thread 重写run
class MyThread extends Thread{
public void run(){
while ( true){
System.out.println("线程");
try {
Thread.sleep(1000);
//.sleep是thread类中的方法,是线程休眠的,休眠时间是毫秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class demo3 {
public static void main(String[] args) throws InterruptedException {
//调用自己的线程类
Thread t = new MyThread();
t.start(); //.start()启动线程
while (true){
System.out.println("线程启动了");
Thread.sleep(1000);
}
}
}
我们就来说说这个代码的重要地方
首先创建一个子类需要继承Thread类,重写其中的run方法,为啥子要在run中书写代码逻辑呢? 实际上.
- run () 是线程真正执行的入口,线程启动后只会自动调用 run (),不会调用你写的其他方法。.start后就会寻找run(),进一步启动线程.
- sleep是Thread类中的静态方法,通过.sleep.让当前线程休眠一会,不会释放锁(后面文章会详细说~*会抛出interruptdedexception异常
- main方法中就是主线程,注意哈,主线程可以理解为我们普通的代码逻辑.是不要start类似的进行调用开始的.main就是开始.
所以嘞上面就是一样的代码逻辑,只不过次线程要想实现就要进程thread类,并且.start启动线程~
执行结果:
- 通过这个执行结果我们也不难方法,这里的调度是随机的,并不是有规律的.
方法2,实现Runnable接口
runnable接口
Runnable 是 Java 提供的一个函数式接口,只有一个抽象方法:run ().作用:专门用来定义线程要执行的任务。
那为什么我们都可以用继承thread类实现多线程了,还要搞一个借口呢
-
最最主要的原因就是java是单继承的 ,如果你的类已经继承了别的类,就不能再 extends Thread .不光是线程的创建,好多其他模式也是多种创建模式~
-
实际上继承的thread类也是实现了runnable接口的,最重要的run方法还是在这个接口中~

Runnable 和 Thread 的关系
Runnable = 任务(要做什么)
Thread = 线程(谁去做)
- 写 Runnable 定义任务,也就是run中代码逻辑~
- 交给 Thread
- 调用 start() 才会真正开线程
java
class MyRunnable implements Runnable{
public void run(){
while (true){
System.out.println("线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class demo4 {
public static void main(String[] args) {
//实例化任务
// Runnable task = new MyRunnable(); 这种只能调用runnable接口的方法
MyRunnable r = new MyRunnable();
Thread t = new Thread(r); //把具体的任务对象作为参数传递给Thread类
t.start();
//主线程
while (true){
System.out.println("线程启动了");
try {
Thread.sleep(1000); //有sleep:主动让出CPU时间片,让其他线程有机会执行
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
我们说一下这个代码细节遇上面的区别
- 上面是在thread中直接run代码逻辑.就是线程中就是有任务栏
- 咱们这个则是先是创建一个任务,然后呢实例化任务的对象,在放在thread类中(存在相关的构造方法,上面有提到啦~)
- 但是下面这个是更加解耦合的,更加推荐~
方法三、匿名内部类创建Thread子类对象
这个本质上与第一个是相同的~.啥是匿名内部类呢?
匿名内部类
- 匿名内部类 = 没有名字、只用一次的类
- 作用 = 少写代码,快速创建接口 / 父类的对象
- 在多线程里 = 快速创建 Runnable 任务,不用单独写类
java
public class demo5 {
//匿名内部类创建Thread子类对象
public static void main(String[] args) {
Thread t = new Thread(){
public void run(){
while (true){
System.out.println("线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
//主线程
while (true){
System.out.println("线程启动了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
方法四、匿名内部类创建Runnable子类对象
java
public class demo6 {
//实现runnable 实现内部类
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t.start();
//主线程
while (true){
System.out.println("线程启动了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
方法五、lambda表达式创建Runnable子类对象(最推荐的),本质上与4相同.
java
public class demo7 {
//lambda表达式创建Runnable子
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true){
System.out.println("线程启动了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
}
}
线程的管理

- 这是大概的过程就是存在一些等待 ,加锁等其他的thread方法让进程进一步一步执行.下面我们就按照创建线程 -> 启动线程 ->中断线程 ,等待线程, 休眠线程这几个状态展开看看.
启动线程.strat
- 启动线程 : 本质上是会调用操作系统的api,在内部创建一个线程出来.一个进程是通过多个pcd进行调度进行的.在java中通过start在操作系统中会创建一个pcb并纳入链表,等待调度,就像进程的范围扩大了
中断线程
- java 中并不提供强制终止,所有的让线程终止的犯法,都是围绕着"让入口方法结束",也就是run方法
有几种常见的控制方法
标志位控制
java
import java.util.Scanner;
public class demo8 {
private static boolean running = true;
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (running){
System.out.println("线程启动了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t线程结束");
});
t.start();
//主线程
Scanner sc = new Scanner(System.in);
System.out.println("请输入1退出线程");
int n = sc.nextInt();
if (n == 1){
running = false;
}
}
}

注意 这里lambda中running是类变量,直接引用来的,会因为外界改变而改变.
但是在lambda内部类中的局部变量捕获是必须是final或者是事实final 没有被修改的.本质上拷贝变量,当外部变量发生变化后,背拷贝的不在随之更改.
Lambda / 匿名内部类中使用的是:
- 类变量(静态变量)、成员变量
→ 直接引用原来的变量
→ 外部修改,内部会跟着变
如果使用的是:
- 局部变量(方法里的变量)
→ 本质是拷贝一份值
→ 必须是 final 或 事实final(没被修改过)
→ 外部后来再变,内部拷贝的不会跟着改
中断机制
java
import java.util.Scanner;
public class demo9 {
public class demo8 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
Thread cur = Thread.currentThread();
//获取当前线程isInterrupted()判断当前线程是否被中断 默认是没有中断的
//默认是false 取反就是 true
while (!cur.isInterrupted()) {
System.out.println("线程启动了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t线程结束");
});
t.start();
//主线程
Scanner sc = new Scanner(System.in);
System.out.println("请输入1退出线程");
int n = sc.nextInt();
if (n == 1) {
t.interrupt(); //使得线程中断
}
}
}
}
java
import java.util.Scanner;
public class demo10 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true) {
System.out.println("线程启动了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
System.out.println("t线程结束");
});
t.start();
//主线程
Scanner sc = new Scanner(System.in);
System.out.println("请输入1退出线程");
int n = sc.nextInt();
if (n == 1) {
t.interrupt(); //使得线程中断
}
}
}
- 注意: interrupt方法会设置标志位false ->true,并且唤醒sleep等阻塞方法,但是一旦sleep唤醒,通过异常的方式返回,回把前线程标志位重新设置为false.设置break即可
等待线程
举一个生活中的例子~
主线程 = 你,t 线程 = 外卖员
t.join() = 你等着外卖员送到,再吃饭
不 join:你该干嘛干嘛,外卖员送他的
join:你卡住不动,一直等外卖员送到
- 需要等待⼀个线程完成它的⼯作后,才能进⾏⾃⼰的下⼀步⼯作 如果调用join之前,t就已经执行完了,此时join就不在堵塞了.
等待线程T
java
public class demo10 {
//主线程等待
private static int result = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
// 子线程计算
for (int i = 0; i < 100; i++) {
result += i;
}
});
t1.start();
t1.join(); // 主线程等待t1执行完毕
System.out.println( result);
int result2 = 0;
//主线程
for (int i = 0; i < 5000; i++) {
result2 += i;
}
System.out.println(result2); // 确保看到最终结果
}
}
等待主线程
java
public class demo10 {
//主线程等待
private static long result = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
// 子线程计算
for (int i = 0; i < 100; i++) {
result += i;
}
});
t1.start();
t1.join(); // 主线程等待子线程执行完毕
System.out.println(result); // 确保打印最终结果
}
}
线程休眠
线程休眠:让当前正在运行的线程暂时停下来,不占用 CPU,等一段时间后再自动恢复运行。
总结
这篇文章就先分享到这里了,希望对你有帮助~
我是Dylan,下次见~
