实现多线程的两种方式
声明
版权声明:本文参考CSDN博主「一个快乐的野指针~」的原创文章,仅用作个人学习,特此声明
原文链接: https://blog.csdn.net/qq_44715943/article/details/116714584
第一种方式
编写一个类,直接 继承 java.lang.Thread,重写 run方法。
- 怎么创建线程对象? new继承线程的类。
- 怎么启动线程呢? 调用线程对象的 start() 方法。
代码
public class ThreadTest {
public static void main(String[] args) {
MyThread t = new MyThread();
// 启动线程
t.run(); // 不会启动线程,不会分配新的分支栈。(这种方式就是单线程。)
//t.start();
//这里的代码还是运行在主线程中。
for(int i = 0; i < 5; i++){
System.out.println("主线程--->" + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
// 编写程序,这段程序运行在分支线程中(分支栈)。
for(int i = 0; i < 10; i++){
System.out.println("分支线程--->" + i);
}
}
}
注意
观察上图发现了一个问题,我已经创建了一个新的分支线程了,为什么还是先走了run方法再走main方法呢?
原来java线程中,run方式和start方式是有区别的
run():在当前线程开启,比如当前线程是主线程,那么运行在主线程,如果当前线程是子线程,那么在子线程运行。还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
start():通过该方法启动线程的同时也创建了一个线程,真正实现了多线程,这是无需等待run()方法中的代码执行完毕就可以直接执行线程外面的代码,通过start创建的线程处于可运行状态,当得到CPU时间片后就会执行其中的run方法, 这里方法run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束, 此线程随即终止。
如下图所示,run方法运行结束,此线程随即终止
总结★★★★★
- t.run() 不会启动线程,只是普通的调用方法而已。不会分配新的分支栈。(这种方式就是单线程。)
- t.start() 方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后,瞬间就结束了。这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开出来,start()方法就结束了。线程就启动成功了。启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)。
run方法在分支栈的栈底部,main方法在主栈的栈底部。run和main是平级的。
注意:以下两张图片由原作者基于其原创代码绘制,在此处仅供学习理解
调用run()方法内存图:
调用start()方法内存图:
第二种方式:
编写一个类,实现 java.lang.Runnable 接口,实现run方法。
- 怎么创建线程对象? new线程类传入可运行的类/接口。
- 怎么启动线程呢? 调用线程对象的 start() 方法。
注意:
第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活。
普通方式
/**
* 实现线程的第二种方式
*/
public class ThreadTest2 {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
// 启动线程
t.start();
for(int i = 0; i < 100; i++){
System.out.println("主线程--->" + i);
}
}
}
// 这并不是一个线程类,是一个可运行的类。它还不是一个线程。
class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("分支线程--->" + i);
}
}
}
采用匿名内部类
/**
* 实现线程的第二种方式:采用匿名内部类
*/
public class ThreadTest3 {
public static void main(String[] args) {
// 创建线程对象,采用匿名内部类方式。
Thread t = new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println("t线程---> " + i);
}
}
});
// 启动线程
t.start();
for(int i = 0; i < 100; i++){
System.out.println("main线程---> " + i);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律