【Java系列】详解多线程(一)

这篇具有很好参考价值的文章主要介绍了【Java系列】详解多线程(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

一、背景引入

在引入多线程之前,我们先来看一下进程是为了干什么的,一句话总结就是:满足"并发编程"这样的需求。

早些时候,CPU都是单核心的CPU,但是随着技术工艺变得越来越强,单核心CPU的性能的确是越来越强的,但是单核心CPU技术工艺研发到一定程度后就会遇到瓶颈,从而导致单核心CPU的研发变得非常缓慢。于是就就逐渐向多核心CPU的方向进行发展研究。

好了,既然CPU逐渐变成了多核心,那么应用程序也应该做出相应的调整来把多核心的CPU给利用起来(意思就是仅仅由硬件上的支撑是不够的,我们还要由软件上的配合),以免造成一核有难,多核围观的场景

另外,早期的系统一般是单任务系统,即在同一时刻只能使用一个程序,而无法在同一时刻内使用多个程序,完成多个任务。而要完成多个任务的话,进程就显得特别关键。

二、线程的引入

多进程能够很好的实现并发编程的效果,但还由一个缺点就是进程太重,即消耗资源更多,速度更慢。如果进程的创建和销毁比较少的话那还勉强可以,但是如果进程的创建和销毁非常频繁的话,此时就会产生非常多的开销。开销大主要体现在需要给进程分配资源,而给进程分配资源的这一过程也是需要很多时间成本的。

于是就有人提出这样一个解决方案:即在创建进程的过程中,只分配简单的PCB(进程控制块),而不去分配后续需要的内存硬盘资源,即把分配资源的时间省去,这样既可以完成多并发编程的任务又能够提升进程创建销毁的速度。

这样一种只分配简单的PCB而不去分配后续需要的内存硬盘资源的这样一种方式称为轻量级进程,也叫做线程(thread)。所以简单来说线程就是只分配PCB,但不分配后续需要的内存硬盘资源

但是线程总归是要完成任务的,如果不去分配后续需要的内存硬盘资源显然是不可以的,于是就有人想出来这样的一个办法:在创建进程的时候,先把后续需要的内存资源分配好;后续创建线程的时候让线程在进程内部直接复用先前进程分配创建好的内存资源(线程和进程直接的关系:进程包含线程)

另外,一个进程至少要包含一个线程,最初进程创建出来的时候,我们可以将这个进程视为一个只包含一个线程的进程(注意此时创建进程的过程是需要分配资源的,同时第一个线程的创建开销是可能是比较大的),我们后续再次创建线程的时候就不需要分配资源了,也就省去了分配资源的过程,因为资源已经是有了的。

小总结

好了,我们已经知道多进程已经可以完成并发编程的任务了,但是由于进程本身有些重,重就体现在进程的创建和销毁所需要的内存硬盘资源开销有些大。

所以就引入了线程(也称为轻量级进程)来更高的解决上述的问题。进程中的多个线程公共复用了进程中的各种内存硬盘等资源,同时这些进程可以各自独立的在CPU中进行调度。所以这样的话线程既可以完成并发编程的效果,又可以以轻量级的方式来完成各种任务。

另外,这里补充一个点,进程和线程是两个不同的概念,在Linux中复用了PCB这个结构体来描述线程,而在Windows中,描述进程和线程是不同的结构体。所以在Windows中,为了更好的描述进程,有时一个PCB对应一个线程,多个PCB对应一个进程(即可能是多一个PCB来描述一个进程,一个PCB来描述一个线程)。

CPU的内存指针和文件描述符表文件描述符表这两个字段内容在同一个进程是一样的,但是上下文信息、状态、优先级、记账信息......等支持调度的属性,这些PCB就不一样了(意思就是每个线程独立去CPU上进行调度,每个线程的上下文、状态、优先级、记账信息等支持调度的属性都有自已独立的一份)。

线程的引入的确能够提高任务执行的速度,同时随着线程数量的增多任务执行完成的速度当然也会增快,但是线程的数量不能是无限制提高的(CPU的核心数的数量是有限的。),同时线程数量也不是越多越好,因为线程调度的开销有时会拖慢整个程序的效率。

两句话总结:

1.进程是操作系统中进行资源分配的基本单位。
2.线程是操作系统中进程调度执行的基本单位。

三、进程和线程的关系(面试题)

1.进程包含线程,都是实现并发编程的一种方式,但是由于多进程的创建和销毁的效率并没有那么高,且线程比进程更加轻量。所以就引入了多线程的概念。

2.进程是系统分派资源的基本单位;线程是是系统调度的基本单位,创建进程的时候已经把分配资源(这里的资源主要指的是虚拟地址空间和符表)的工作做了,后续创建进程的时候直接复用之前的资源即可。

3.每个进程都有自己独立的地址空间,彼此直接不会相会影响到,从而保证了每个进程的独立性,保证了数据稳定性。
需要注意的是,如果多个组线程程共用了一份地址空间的话,一旦某个线程抛出异常的话,就可能会导致一整个进程结束(所以多个线程之间是很容易相互影响的。 )。

四、第一个多线程程序

线程本身是操作系统的概念,而操作系统又提供了API来供我们使用线程,来完成多线程编程(在Linux中称为pthread库,通过这个库我们就可以完成多线程编程)。

而在Java中,把操作系统中的API进程分装,即提供了Thread类来帮助哦我们来完成多线程编程。

Java标准库中的Thread类来自于java.lang这个包,而Java.lang这个包不需要我们手动的import

好了,光说不练是不行的,接下来我们就来看一下我们的第一个线程程序,请看下图:

package thread;

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Hello,world!");
    }
}

public class Demo01 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

现在我们来解释上述的线程程序,上述代码的MyThread类中的run()方法是重写的Thread父类中的run()方法,这个run()方法相当于线程程序的入口,线程程序跑起来之后具体要干什么事情,都是通过这个run()方法来进行描述的。

myThread.start()这个操作就是在创建一个线程(即在底层调用操作系统提供的创建线程的API,同时在操作系统内核中创建出其对应的PCB结构,并将其加入到链表中)。此时这个新创建出来的线程就会参与到cpu的调度中,接下来线程要执行的任务,就是run()方法中的内容。

接下来我如果注释掉myThread.start();,即直接执行MyThread类中的run()方法,请看下图:
【Java系列】详解多线程(一),Java系列,JavaEE学习专栏,java,开发语言,java-ee
我们来解释上述程序,我们前面已经知道,start方法会去调用操作系统提供的创建线程的API,同时在操作系统内核中创建出其所对应的PCB,此时这个新创建出来的线程就会参与cpu调度
而我们直接运行run方法的话,此时并没有调用操作系统提供的创建线程的API,也就没有创建出新的进程。
当整个程序开始运行的时候,此时会先创建出来一个java进程,这个java进程中至少包含一个进程,称为主进程,这个主进程是负责执行main()方法的线程。每一个线程都能够被独立的进行调用和执行。

每个线程都能够被独立的进行调用执行

每个线程都能够被独立的进行调用执行,现在我们来写一个程序来体现这句话。请看:

【Java系列】详解多线程(一),Java系列,JavaEE学习专栏,java,开发语言,java-ee
运行结果如下(由于程序是一个死循环,所以这里只是截取了部分的程序运行结果),如下图:
【Java系列】详解多线程(一),Java系列,JavaEE学习专栏,java,开发语言,java-ee
我们可以看到程序一会执行Hello,Linux!一会执行Hello,world!
解释:start()是新线程执行的入口,而主线程和新线程是并发执行的一个关系。先新创建出来的线程创建出来之后会执行run()方法中的代码,而main()方法则是继续往后执行。所以最终呈现出来的程序运行效果就是一会执行Hello,Linux!,一会执行Hello,world!

现在我们在来看一段程序,请看下图:
【Java系列】详解多线程(一),Java系列,JavaEE学习专栏,java,开发语言,java-ee
我们可以看到上述代码把myThread.start()注释掉了,相当于我们并没有创建线程,那么此时的话只有整个程序只有主线程这一个线程了。
分析到这里我们已经知道整个程序只有线程(也就是主线程),那么执行的run()方法就是在主线程中去执行的,因为整个程序就只有一个线程(即主线程)。

总结一下:

  • 每个线程都是一个独立的执行流。
  • 每个线程都可以执行一段代码。
  • 每个线程之间是并发的关系。

好了,本文到这里就结束了,就到这里吧,再见啦友友们!!!【Java系列】详解多线程(一),Java系列,JavaEE学习专栏,java,开发语言,java-ee文章来源地址https://www.toymoban.com/news/detail-751581.html

到了这里,关于【Java系列】详解多线程(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaEE初阶:Java线程的状态

    目录 获取当前线程引用 休眠当前线程  线程的状态 1.NEW               2.TERMINATED  3.RUNNABLE 4.WAITING 5.TIMED_WAITING 6.BLOCKED 多线程的意义 单线程  多线程 这个方法返回当前线程的引用。但是我们会对static有疑惑,这其实是一个静态方法,更好的说法是这是一个 类方法, 调用这

    2024年02月11日
    浏览(30)
  • Java多线程开发系列之六:无限分解流----Fork/Join框架

    Fork译为拆分,Join译为合并 Fork/Join框架的思路是把一个非常巨大的任务,拆分成若然的小任务,再由小任务继续拆解。直至达到一个相对合理的任务粒度。然后执行获得结果,然后将这些小任务的结果汇总,生成大任务的结果, 直至汇总成最初巨大任务的结果。如下图: 红

    2024年02月08日
    浏览(26)
  • 【JavaEE】Java中的多线程 (Thread类)

    作者主页: paper jie_博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将基础知识一网打尽,希望可以帮到读者们哦。 其他专栏:《MySQL》《

    2024年02月05日
    浏览(43)
  • 【Java系列】多线程案例学习——基于阻塞队列实现生产者消费者模型

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习JavaEE的一点学习心得,欢迎大家在评论区交流讨论💌 什么是阻塞式队列(有两点): 第一点:当队列满的时候

    2024年02月04日
    浏览(39)
  • 【JavaEE】什么是多线程?进程和线程的区别是什么?如何使用Java实现多线程?

    前面我们了解了什么是进程以及如何实现进程调度,那么今天我将为大家分享关于线程相关的知识。在学习线程之前,我们认为进程是操作系统执行独立执行的单位,但其实并不然。线程是操作系统中能够独立执行的最小单元。只有掌握了什么是线程,我们才能实现后面的并

    2024年02月09日
    浏览(38)
  • 【JavaEE】JUC(java.util.concurrent)的常见类以及线程安全的集合类

    目录 1、JUC(java.util.concurrent)的常见类 1.1、Callable接口的用法(创建线程的一种写法)  1.2、ReentrantLock可重入互斥锁 1.2.1、ReentrantLock和synchronized的区别  1.2.2、如何选择使用哪个锁 1.3、Semaphore信号量 1.4、CountDownLatch  2、线程安全的集合类 2.1、多线程环境使用ArrayList  2.2、

    2024年02月07日
    浏览(37)
  • 【JavaEE基础学习打卡00】该专栏知识大纲在这里!

    📜 本系列教程适用于 Java Web 初学者、爱好者,小白白。我们的天赋并不高,可贵在努力,坚持不放弃。坚信量最终引发质变,厚积薄发。 🚀 文中白话居多,尽量以小白视角呈现,帮助大家快速入门。 🎅 我是 蜗牛老师 ,之前网名是 Ongoing蜗牛 ,人如其名,干啥都慢,所

    2024年02月10日
    浏览(24)
  • 【Java 线程系列】Java 天生就是多线程

    作者:半身风雪 上一篇:线程之间的共享和协作

    2024年02月05日
    浏览(39)
  • 多线程(JavaEE初阶系列4)

    目录 前言: 1.单例模式 1.1饿汉模式 1.2懒汉模式 1.3结合线程安全下的单例模式 1.4单例模式总结 2.阻塞式队列 2.1什么是阻塞队列 2.2生产者消费者模型 2.2.1 上下游模块之间进行“解耦合” 2.2.2削峰填谷 2.3阻塞队列的实现 结束语: 在上节中小编主要与大家分享了多线程中遇到

    2024年02月15日
    浏览(41)
  • 多线程(JavaEE初阶系列7)

    目录 前言: 1.常见的锁策略 1.1乐观锁和悲观锁 1.2轻量级锁和重量级锁 1.3自旋锁和挂起等待锁 1.4互斥锁与读写锁 1.5可重入锁与不可重入锁 1.6公平锁与非公平锁 2.CAS 2.1什么是CAS 2.2自旋锁的实现 2.3原子类 3.synchronized 3.1synchronized的原理以及基本特点 3.2偏向锁 3.3轻量级锁 3.4重

    2024年02月14日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包