文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【Java系列】详解多线程(二)——Thread类及常见方法(上篇)

2023-12-23 07:44

关注

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【Java系列专栏】【JaveEE学习专栏
本专栏旨在分享学习Java的一点学习心得,欢迎大家在评论区交流讨论💌

一、前文回顾

我们先来回顾一下线程与进程之间的联系。

我们知道多进程可以帮助我们完成并发编程,即可以把多个cpu核心充分利用起来以完成同时执行多任务的场景。但是进程有一个问题就是进程的创建和销毁的开销是比较大的,如果我们需要频繁的创建和销毁进程的话,那么多进程这种方式就是比较低效的。所以就衍生出了轻量级进程——线程。线程之所以比进程更轻量级主要有两方面的原因

线程在同一进程内共享内存资源,所以当进程创建完成时,线程已经可以访问和共享这些内存资源(主线程是在进程创建时默认创建的一个线程)。如果后续需要我们创建其它的线程,我们就可以重用之前的字眼就可以了。

进程包含了线程,一个进程内部至少有一个线程,进程是系统中分配资源的基本单位,而线程是cpu调度执行的基本单位。我们可以这样说线程的引入最主要的就是为了实现更高效的并发处理和资源共享。

由于线程可以共享同一进程内的内存资源,因此资源分配的主要任务是为进程分配足够的内存空间,对线程的资源分配比在进程级别上的资源分配要少得多。

现在问题来了,一个进程内既然可以存在多个线程,同时线程可以共享同一个进程内的资源,这也意味着这多个线程之间的相互干扰会比较大(这一点就不如进程之间那样相对独立一些,一个进程挂掉知道后不会对其它进程产生影响。),一旦某个出现异常之后就有可能导致整个进程都会挂掉,这当然会对其它线程产生影响。另外,多个线程去访问同一块公共资源的时候也可能会出现冲突带来线程安全的问题。

所以,总的来说使用多线程的方式完成任务比多进程的方式完成任务会有优势,但同时存在一些缺点。但尽管如此,我们依然可以利用多线程的方式来很好的完成并发编程的任务。

好了,友友们,回顾到此结束,接下来我们一起学习新的内容吧!!!

二、创建线程的几种方式。

Java标准库中,提供了Thread()类来表示线程,同时Java创建线程的方式有很多种。最常见的两种写法:继承Thread()类重写Runnable方法()

继承Thread类

方式一:通过继承thread类来重写run方法是一种创建线程的方式(这里我们需要自己创建一个类来继承thread方法);方式二:还有一种方式我们也可以创建线程:基于匿名内部类的形式来继承thread类,并重run方法。

现在我们通过匿名内部类的方式来创建线程(基于匿名内部类的形式来继承thread类,并重写run方法,即方式二):

代码如下:

public class Demo03 {    public static void main(String[] args) {        Thread t = new Thread() {            @Override            public void run() {                while(true) {                    System.out.println("hello thread!!!");                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        throw new RuntimeException(e);                    }                }            }        };        t.start();    }}

解释:上述代码中我们创建了一个子类,这个子类(此类就是我们说的匿名内部类)继承自Thread类,同时我们在这个子类重对run方法进行了重写。
另外我们还创建了该子类(也就是之前说的匿名内部类)的实例,用引用t类指向这个实例。
最后就是通过引用t来调用start方法来调用系统API,再从内核中把线程创建出来。
在这里插入图片描述
最后我们来看一下运行结果:
在这里插入图片描述

实现runnable方法

方式三通过实现runnable来重写run方法(这里是自己创建一个类)的方式可以创建一个线程。方式四:另外我们这里依然可以用其它方式来创建一个线程:即基于匿名内部类的形式来实现runnable并重写run方法。

现在我们通过匿名内部类的形式来实现runnable并重写run方法(即方式四)来创建线程,代码如下:

public class Demo04 {    public static void main(String[] args) {        Thread t = new Thread(new Runnable() {            @Override            public void run() {                while(true) {                    System.out.println("hello world");                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        throw new RuntimeException(e);                    }                }            }        });        t.start();    }}

解释,上述代码中,我们创建了runnable的子类,并重写了run方法,然后创建出了runnable的子类的实例,把这个实例传给Thread的构造方法。

lambda表达式

我们还可以通过lambda表达式来表示run方法的内容,从而创建出线程。

代码如下:

public class Demo05 {    public static void main(String[] args) {        Thread t = new Thread(() -> {            while(true) {                System.out.println("hello world");                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }            }        });        t.start();    }}

什么是lambda表达式:lambda表达式本质上就是一个匿名函数,主要可以用来作为回调函数来进行使用。
先来回顾一下回调函数吧:回调函数不需要我们自己去进行调用,因为回调函数会在特定的时机自动地被调用。
此时的回调函数就是在线程创建成功之后才会真正执行。

关于线程的创建这里,也有其它的方式,比如基于callable的方式创建线程,基于线程池的方式创建线程。

三、Thread类及常见方法

Thread类是JVM用来管理线程的一个类,换句话说,每个线程都有一个唯一的Thread对象与之关联。我们对线程的各种操作都是根据Thread类进行展开的。

Thread类的常见构造方法

这里我们可以参照Java官方文档:https://docs.oracle.com/javase/8/docs/api/index.html
在这里插入图片描述

在这里插入图片描述

如下图的代码中,我们给线程起了个名字mythread
在这里插入图片描述
我们可以通过JVM中的jconsole.exe来看到这个线程(mythread):
在这里插入图片描述
现在问题来了,为什么我们没有看到主线程(main)呢?在上述代码中,主线程创建并启动了一个新线程,而新线程负责打印"hello thread"的消息。由于新线程的循环中有一个线程休眠的操作(Thread.sleep(1000)),所以您将会在不同时间间隔内看到"hello thread"的输出。但这个输出是由新线程负责的,而不是主线程。
所以,我们没有看到主线程的原因是主线程没有显示任何输出或执行其他代码来表明它的存在。它仅仅完成了创建和启动新线程的任务,然后退出。
对于主线程来说,main方法就是主线程的入口;而对于其它线程来说,lambda或者run就是线程的入口。所以执行完线程的入口函数,线程就算是结束了。

Thread类的属性

下面是Thread类的几个常见属性:

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDasmon()
是否存活isAlive()
是否被中断isInterrupted()
// 这里我们创建的线程是前台线程public class Demo07 {    public static void main(String[] args) {        Thread t = new Thread(()->{            while(true) {                System.out.println("hello thread!!!");            }        });        t.start();    }}// 这里将我们创建的线程设置为了后台线程public class Demo07 {    public static void main(String[] args) {        Thread t = new Thread(()->{            while(true) {                System.out.println("hello thread!!!");            }        });        t.setDaemon(true);        t.start();    }}

当我们把创建的线程设置为后台线程之后,程序运行起来之后就会立即结束。原因:由于我们把自己手动的线程创建成了后台线程,所以此时就只剩下main主线程了,而main线程这里不需要执行代码,所以执行时间极短main线程(前台线程)就结束了,而我们设置的后台线程还没有来得及执行就随着进程的退出而退出了。

好了,本文到这里就结束了,希望友友们可以支持一下一键三连哈。嗯,就到这里吧,再见啦!!!

在这里插入图片描述

来源地址:https://blog.csdn.net/m0_74352571/article/details/134962573

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯