JavaEE-多线程实战01
Java 多线程入门:第一个多线程程序
在 Java 中,多线程编程是非常重要的一部分。本篇文章将通过示例,带你快速了解如何创建第一个多线程程序,并深入分析其运行机制。
1. 创建一个线程类并继承 Thread
在 Java 中,我们可以通过继承 Thread
类并重写其中的 run()
方法,来定义一个自己的线程行为。
来看第一个示例:
package thread.test;//1.创建一个自己的类,继承自这个Thread
class MyThread extends Thread {@Overridepublic void run() {//run方法就是这个线程的入口方法,类似于main()System.out.println("hello world");}
}public class ThreadDemo1 {public static void main(String[] args) {//2.根据自定义的类创建出实例(线程实例才是真正的线程)//也可以用MyThread t=new MyThread();Thread thread=new MyThread();//3.调用Thread的start方法,才会真正调用系统api,在系统内核中创建出线程//使用Thread会创建出线程,而直接使用run的话就不会thread.start();}
}
运行结果
2. 代码分析
当你调用 thread.start()
时,真正开辟了一个新的线程,系统会去执行 MyThread
类的 run()
方法里的代码(即打印 "hello world")。
注意,调用的是 start()
方法,而不是直接调用 run()
,这是两者最关键的区别!
-
start()
方法通知系统启动一个新线程,不会阻塞当前主线程。 -
run()
方法只是一个普通的方法调用,不会开启新的线程。
所以,main()
方法会快速执行完,而子线程仍在后台执行。主线程和子线程各自独立运行。
3. 再举一个例子:多线程并发执行
来看另一个简单示例,理解并发执行的效果:
public class Example {public static void main(String[] args) {MyThread t = new MyThread();t.start();System.out.println("main线程结束了");}
}
class MyThread extends Thread {@Overridepublic void run() {System.out.println("我是子线程");}
}
可能输出结果是:
也可能输出的结果是:
为什么会有两种可能?
因为多线程执行是并发的,谁先执行完是不确定的,由操作系统线程调度器决定。
4. 小知识:守护线程(Daemon Thread)
在 Java 中,普通线程会阻止整个程序结束。而守护线程不会。
整个进程(整个程序)是不是结束,要看有没有别的 非守护线程 还在运行!
具体来说:
-
如果还有其他普通线程(非守护线程)在运行,进程不会结束。
-
只有当所有非守护线程都结束以后,整个 Java 进程才真正结束。
-
守护线程(daemon thread)不会阻止进程结束(守护线程就像后台服务一样,进程结束了它也跟着挂了)。
如果你希望让子线程是“守护线程”,可以这样写:
MyThread thread = new MyThread();
thread.setDaemon(true); // 设置成守护线程
thread.start();
这样,当主线程执行完毕后,即使子线程还没跑完,整个进程也会直接结束!
注意:setDaemon(true)
必须在 start()
之前调用,否则会抛异常!
Java 多线程入门:第二个多线程程序
接下来,我们来写一个持续运行的线程,看看主线程和子线程如何同时运行、轮流输出内容。
5. 代码示例:两个线程同时输出内容
package thread.test;class MyThread2 extends Thread {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo2 {public static void main(String[] args) {Thread t=new MyThread2();t.start();while (true) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
执行结果
代码分析
6. 代码分析
-
MyThread2
是一个自定义线程类,重写了run()
方法。 -
子线程每隔 1 秒输出一次
"hello thread"
。 -
主线程(
main
方法)每隔 1 秒输出一次"hello main"
。
运行效果示例:
由于是两个独立的线程,它们的输出顺序和精确时间点可能不一样,比如:
有时先看到 "hello main"
有时先看到 "hello thread"
这种不确定性就是并发执行的本质特征!