目录
1.认识线程
线程是什么
为什么要有线程
进程和线程的区别
java中的主线程
jconsole观察线程
2.创建线程
方法1——继承Thread类
方法2——实现Runnable接口
方法三——使用匿名内部类创建线程
使用Lambda 表达式创建线程
3.Thread类及常见方法
Thread类的概念
Thread 的常见构造方法
Thread 的几个常见属性
1.认识线程
线程是什么
一个线程就是一个 " 执行流 ". 每个线程之间都可以按照顺序执行自己的代码 . 多个线程之间 " 同时 " 执行着多份代码。
我们设想如下场景:
一家公司要去银行办理业务,既要进行财务转账,又要进行福利发放,还得进行缴社保。如果只有张三一个会计就会忙不过来,耗费的时间特别长。为了让业务更快的办理好,张三又找来两位同事李四、王五一起来帮助他,三个人分别负责一个事情,分别申请一个号码进行排队,自此就有了三个执行流共同完成任务,但本质上他们都是为了办理一家公司的业务。此时,我们就把这种情况称为多线程,将一个大任务分解成不同小任务,交给不同执行流就分别排队执行。其中李四、王五都是张三叫来的,所以张三一般被称为主线程(Main Thread),而公司就相当于进程,其中的员工属于线程
为什么要有线程
首先, "并发编程" 成为 刚需。
- 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU,而并发编程能更充分利用多核 CPU资源。
- 有些任务场景需要 "等待 IO", 为了让等待 IO 的时间能够去做一些其他的工作, 也需要用到并发编程。
- 其次, 虽然多进程也能实现并发编程, 但是线程比进程更轻量。线程是轻量级进程。
- 创建线程比创建进程更快。
- 销毁线程比销毁进程更快。
- 调度线程比调度进程更快。
进程和线程的区别
- 进程是包含线程的,每个进程至少有一个线程存在。
- 进程和进程之间不共享内存空间,同一个进程的线程之间共享同一个内存空间。
- 进程是系统分配资源的最小单位,线程是系统调度的最小单位。
java中的主线程
对于java中自带一个主线程,main就是java的主线程,在其里面的代码都是主线程中的任务
jconsole观察线程
我们可以通过jconsole这个工具去观察线程,至于怎么使用,这里有一篇文章写的很好:
观测线程的工具——jconsole_观测电脑线程-CSDN博客
2.创建线程
创建线程有三种方法:
方法1——继承Thread类
通过继承
Thread
类并重写run()
方法来创建线程。class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running (Thread Class)");System.out.println("Thread name: " + Thread.currentThread().getName());} }public class Main {public static void main(String[] args) {Thread thread = new MyThread();thread.start(); // 启动线程} }
方法2——实现Runnable接口
通过实现
Runnable
接口来定义线程任务。class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Thread is running (Runnable)");System.out.println("Thread name: " + Thread.currentThread().getName());} }public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start(); // 启动线程} }
在讲完这两个方法后,我们发现run和start两个重要方法,那么它们是干什么的?
run里面用于描述线程干什么任务,通过 start 去创建线程而后执行该任务。
start是Thread中自带的方法,通俗的来说run方法记录这个"事情",而strat就是要执行run里面的"事情"
如果不去调用start,直接调用run的话,就没有创建出新的线程,就是在主线程中执行run任务。
方法三——使用匿名内部类创建线程
实际上还是方法一和方法二的描述,简化了代码罢了
public class Main {public static void main(String[] args) {// 使用匿名内部类继承 ThreadThread thread = new Thread() {@Overridepublic void run() {System.out.println("Thread is running (Thread - Anonymous Inner Class)");System.out.println("Thread name: " + Thread.currentThread().getName());}};// 启动线程thread.start();}
}
public class Main {public static void main(String[] args) {// 使用匿名内部类实现 RunnableRunnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("Thread is running (Runnable - Anonymous Inner Class)");System.out.println("Thread name: " + Thread.currentThread().getName());}};// 创建线程并启动Thread thread = new Thread(runnable);thread.start();}
}
使用Lambda 表达式创建线程
这个方法实际上还是方法二,简化了内部类罢了,这里不做解释了,数据结构内容
由于
Thread
类本身不是函数式接口,所以无法直接使用 Lambda 表达式忘记的同学可以看看大佬博客:【Java数据结构】反射、枚举以及lambda表达式_反射构建lamda fun-CSDN博客
3.Thread类及常见方法
Thread类的概念
我们在前面看到了线程的创建需要Thread类,那么Thread类到底是什么呢?
Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
每个执行流,也需要有一个对象来描述,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理
Thread 的常见构造方法
Thread 的几个常见属性
常见属性说明:
- ID 是线程的唯一标识,不同线程不会重复,这里的id和pcb的id是不同的,是jvm自己搞的一套体系,Java代码也无法获取到pcb的id
- 关于后台线程,需要记住一点:JVM会在一个进程的所有前台线程结束后,才会结束运行。而后台线程无论结束还是不结束,都不影响jvm结束运行
-
在 java 代码中, main 线程, 就是前台线程另外程序员创建出来的线程,默认情况下都是 前台线程.可以通过上述 setDaemon 方法来把线程设置为后台线程
在 jconsole 中看到的 jvm 中包含一些其他的内置的线程, 就属于后台线程。我不期望这个线程影响JVM的结束,就设为后台线程,举个例子,比如,有的线程负责进行 gc. (垃圾回收),gc 是要周期性持续性执行的.不可能主动结束,要是把他设为前台,进程就永远也结束不了 -
是否存活,很直白的意思,就是线程是否还存在
-
是否被中断(isInterrupted)这个属性之后在中断会讲到,这里先打个哑谜。