欢迎阅读前序课程JavaEE 多线程第二节 (多线程的简单实现Thread/Runable)-CSDN博客
1. lambda方法实现多线程
java
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while (true){
System.out.println("helloworld");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
while (true){
System.out.println("Hello Main");
Thread.sleep(1000);
}
}
}
2. Thread属性和方法
1. 属性----->名称
java
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while (true){
System.out.println("helloworld");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"自定义线程");
t.start();
while (true){
System.out.println("Hello Main");
Thread.sleep(1000);
}
}
}
可以从jconsole查看
2.方法
java
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while (true){
System.out.println("helloworld");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"自定义线程");
t.start();
System.out.println("线程ID"+ t.getId());
System.out.println("线程名字"+ t.getName());
System.out.println("线程状态"+ t.getState());
System.out.println("线程优先级"+t.getPriority());
}
}
isAlive
运行结果:
- 在
t.start()
之前,t.isAlive()
返回false
,因为线程还没有启动。 - 调用
t.start()
之后,线程开始执行任务,此时t.isAlive()
返回true
。 - 主线程通过
Thread.sleep(5000)
休眠 5 秒,确保给线程 t 足够的时间去完成任务(线程 t 每次休眠 1 秒,总共循环 3 次,因此需要约 3 秒完成)。 - 当
t
线程的任务执行完后,t.isAlive()
再次返回false
,因为线程已经结束。
关键点:
- 线程状态 :
isAlive()
方法用于检查线程是否还在运行。当线程启动并未终止时,返回true
;否则返回false
。
- 线程执行过程 :
- 你创建了一个线程
t
,其任务是在循环中打印"helloworld"
三次,每次打印后休眠 1 秒。通过t.start()
启动线程,JVM 会为这个线程分配时间片执行任务。
- 你创建了一个线程
- 线程的生命周期 :
- 线程的状态会经历几个阶段:
- 新建状态(New) :线程
t
刚创建时,还未调用start()
。 - 就绪状态(Runnable) :调用
start()
之后,线程进入就绪状态,等待 JVM 调度执行。 - 运行状态(Running) :线程被调度并开始执行
run()
方法中的代码。 - 终止状态(Terminated) :当
run()
方法执行完毕,线程进入终止状态,此时isAlive()
返回false
。
- 新建状态(New) :线程
- 线程的状态会经历几个阶段:
3. 前台线程后台线程
1. 前台线程 vs 后台线程
-
前台线程(用户线程):
- 默认情况下,Java中的线程都是前台线程。
- JVM不会终止,直到所有前台线程都结束。如果有任何前台线程还在运行,JVM会继续执行。
- 举例:在你的代码中,如果你不调用
t.setDaemon(true)
,线程t
就是一个前台线程,意味着即使main
方法结束,JVM也不会退出,因为t
线程在不停地输出"helloworld"
。
-
后台线程(守护线程):
- 后台线程通常是为其他线程提供服务的线程,比如垃圾回收线程。
- JVM会在所有前台线程都结束后终止,不管后台线程是否还在运行。
- 通过
Thread.setDaemon(true)
将一个线程设为后台线程。 - 如果你设置了
t.setDaemon(true)
,意味着t
是一个后台线程,当main
线程(前台线程)结束后,JVM会终止,后台线程t
也会随之停止,不再继续运行。
2. 结合代码讲解
java
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while (true){
System.out.println("helloworld");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"自定义线程");
t.setDaemon(true);
t.start();
//t变为守护线程不能组织线程结束
}
}
运行一次就结束了
3. 执行流程
Thread t
是一个线程对象,线程的任务是通过lambda
表达式定义的,循环输出"helloworld"
并每秒钟休眠一次。t.setDaemon(true)
这行代码将t
线程设为守护线程 。这意味着,当所有前台线程结束时 ,守护线程t
也会结束,而不管它是否仍然在运行。t.start()
启动线程t
,线程进入运行状态,开始打印"helloworld"
。- 重点 :由于
t
是后台线程,当main
方法执行结束,JVM 会停止所有后台线程并终止运行。因此,t
的运行时间会非常短暂。
4. 前台和后台线程的区别总结
- 前台线程 (用户线程):
- 会阻止 JVM 退出。
- 即使所有后台线程结束,前台线程还在运行,JVM 也不会停止。
- 后台线程 (守护线程):
- 当所有前台线程结束时,JVM 会终止,即使后台线程还在运行。
- 守护线程通常用于执行一些后台服务,比如垃圾回收。
5. 关于这段代码的实际行为
如果你将 t.setDaemon(true)
改为 t.setDaemon(false)
(或者直接不调用它,默认是前台线程),t
就变为前台线程。此时,即使 main
线程结束,JVM 也会继续运行,因为 t
线程还在运行,它会一直每秒钟输出 "helloworld"
。
然而,使用了 t.setDaemon(true)
后,t
成为后台线程。当 main
线程结束时,t
线程会立即终止,不再输出 "helloworld"
。
总结:
- 守护线程通常用于执行后台任务或辅助功能(如垃圾回收器),它不应该是程序的核心逻辑。
- 用户线程(前台线程)是程序的核心工作线程,确保程序在完成任务后才退出。