关于线程和线程池的学习,我们可以从以下几个方面入手:

第一,什么是线程,线程和进程的区别是什么

第二,线程中的基本概念,线程的生命周期

第三,单线程和多线程

第四,线程池的原理解析

第五,常见的几种线程池的特点以及各自的应用场景

一、

线程,程序执行流的最小执行单位,是行程中的实际运作单位,经常容易和进程这个概念混淆。

那么,线程和进程究竟有什么区别呢?首先,进程是一个动态的过程,是一个活动的实体。

简单来说,一个应用程序的运行就可以被看做是一个进程,而线程,是运行中的实际的任务执行者。

可以说,进程中包含了多个可以同时运行的线程。

二、

线程的生命周期,线程的生命周期可以利用以下的图解来更好的理解:

第一步,是用new Thread()的方法新建一个线程,在线程创建完成之后,线程就进入了就绪(Runnable)状态,此时创建出来的线程进入抢占CPU资源的状态,

当线程抢到了CPU的执行权之后,线程就进入了运行状态(Running),当该线程的任务执行完成之后或者是非常态的调用的stop()方法之后,线程就进入了死亡状态。

而我们在图解中可以看出,线程还具有一个阻塞的过程,这是怎么回事呢?

当面对以下几种情况的时候,容易造成线程阻塞,第一种,当线程主动调用了sleep()方法时,线程会进入则阻塞状态;

除此之外,当线程中主动调用了阻塞时的IO方法时,这个方法有一个返回参数,当参数返回之前,线程也会进入阻塞状态;

还有一种情况,当线程进入正在等待某个通知时,会进入阻塞状态。

那么,为什么会有阻塞状态出现呢?

我们都知道,CPU的资源是十分宝贵的,所以,当线程正在进行某种不确定时长的任务时,Java就会收回CPU的执行权,从而合理应用CPU的资源。

我们根据图可以看出,线程在阻塞过程结束之后,会重新进入就绪状态,重新抢夺CPU资源。

这时候,我们可能会产生一个疑问,如何跳出阻塞过程呢?

以上几种可能造成线程阻塞的情况来看,都是存在一个时间限制的,当sleep()方法的睡眠时长过去后,线程就自动跳出了阻塞状态,

第二种则是在返回了一个参数之后,在获取到了等待的通知时,就自动跳出了线程的阻塞过程。

三、

什么是单线程和多线程?

单线程,顾名思义即是只有一条线程在执行任务,这种情况在我们日常的工作学习中很少遇到,所以我们只是简单做一下了解。

多线程,创建多条线程同时执行任务,这种方式在我们的日常生活中比较常见。

但是,在多线程的使用过程中,还有许多需要我们了解的概念。

比如,在理解上并行和并发的区别,以及在实际应用的过程中多线程的安全问题,对此,我们需要进行详细的了解。

还有就是多线程的安全问题?

为什么会造成多线程的安全问题呢?

我们可以想象一下,如果多个线程同时执行一个任务,那么意味着他们共享同一种资源,由于线程CPU的资源不一定可以被谁抢占到,

这时,第一条线程先抢占到CPU资源,他刚刚进行了第一次操作,而此时第二条线程抢占到了CPU的资源,

那么,共享资源还来不及发生变化,就同时有两条数据使用了同一条资源,具体请参考多线程买票问题。这个问题我们应该如何解决那?

有造成问题的原因我们可以看出,这个问题主要的矛盾在于,CPU的使用权抢占和资源的共享发生了冲突,

解决时,我们只需要让一条线程占用了CPU的资源时,阻止第二条线程同时抢占CPU的执行权,在代码中,我们只需要在方法中使用同步代码块即可。

补充:并行与并发的区别:

理解并发、并行的例子

先举例子来理解这2个概念的区别。

老师让两个同学去办公室谈话。如果这两同学(进程)是并列跨过办公室门(CPU)的,那么就是并行。

如果同学A先进同学B后进入(或者先B后A),或者两人并列同时进入,但是在办公室外的路人甲(用户)看来,同学A和同学B同时都在办公室内,这是并发。

其实这个例子不合理,因为真正的并行是多核CPU下的概念,但上面这个简单的例子非常有助于理解。

如果举例要精确一点,那么大概是这样的:

进办公室有两个门(两CPU),如果两同学分别从不同的门进入,不管先后性,两者互相独立,那么是并行;

如果两同学不管以什么方式进入,在路人甲看来,他两同时都在办公室内,就是并发。

我不信到现在还不理解并发和并行。

并发和并行的理论性解释

为什么操作系统上可以同时运行多个程序而用户感觉不出来?

这是因为无论是单CPU还是多CPU,操作系统都营造出了可以同时运行多个程序的假象

实际的过程操作系统对进程的调度以及CPU的快速上下文切换实现的:每个进程执行一会就先停下来,然后CPU切换到下个被操作系统调度到的进程上使之运行

因为切换的很快,使得用户认为操作系统一直在服务自己的程序。

再来解释并发就容易理解多了。

并发(concurrent)指的是多个程序可以同时运行的现象,更细化的是多进程可以同时运行或者多指令可以同时运行。

但这不是重点,在描述并发的时候也不会去扣这种字眼是否精确,并发的重点在于它是一种现象。

并发描述的是多进程同时运行的现象。但实际上,对于单核心CPU来说,同一时刻只能运行一个进程。

所以,这里的"同时运行"表示的不是真的同一时刻有多个进程运行的现象,这是并行的概念,

而是提供一种功能让用户看来多个程序同时运行起来了,但实际上这些程序中的进程不是一直霸占CPU的,而是执行一会停一会。

所以,并发和并行的区别就很明显了。它们虽然都说是"多个进程同时运行",但是它们的"同时"不是一个概念。

并行的"同时"是同一时刻可以多个进程在运行(处于running)。

并发的"同时"是经过上下文快速切换,使得看上去多个进程同时都在运行的现象,是一种OS欺骗用户的现象

实际上,当程序中写下多进程或多线程代码时,这意味着的是并发而不是并行

并发是因为多进程/多线程都是需要去完成的任务,不并行是因为并行与否由操作系统的调度器决定,可能会让多个进程/线程被调度到同一个CPU核心上。

只不过调度算法会尽量让不同进程/线程使用不同的CPU核心,所以在实际使用中几乎总是会并行,但却不能以100%的角度去保证会并行。

也就是说,并行与否程序员无法控制,只能让操作系统决定

再次注明,并发是一种现象,之所以能有这种现象的存在,和CPU的多少无关,而是和进程调度以及上下文切换有关的。

并行模式

并行意味着可以同时取得多个任务,并同时去执行所取得的这些任务。并行模式相当于将长长的一条队列,划分成了多条短队列,所以并行缩短了任务队列的长度

正如前面所举的两同学进办公室的例子,串行的方式下,必须1个同学进入后第二个同学才进入,队列长度为2,而并行方式下可以同时进入,队列长度减半了。

并行的效率从代码层次上强依赖于多进程/多线程代码,从硬件角度上则依赖于多核CPU

对于单进程/单线程,由于只有一个进程/线程在执行,所以尽管同时执行所取得的多个任务,但实际上这个进程/线程是不断的在多任务之间切换,一会执行一下这个,一会执行一下那个,就像是一个人在不同地方之间来回奔波。所以,单进程/线程的并行,效率比串行更低。

对于多进程/多线程,各进程/线程都可以执行各自所取得的任务,这是真正的并行。

但是,还需要考虑硬件层次上CPU核心数,如果只有单核CPU,那么在硬件角度上这单核CPU一次也只能执行一个任务,上面多进程/多线程的并行也并非真正意义上的并行。

只有多核CPU,并且多进程/多线程并行,才是真正意义上的并行。

并发

并发表示多个任务同时都要执行的现象,更详细的概念前面已经说面的够具体了。

其实,很多场景下都会使用并发的概念。比如同时500个http请求涌向了web服务器,比如有时候说并发数是1000等。

有时候也将并发当成任务,比如500并发数意味着500个任务,表示的是在一个特定的时间段内(约定俗成的大家认为是1秒)可以完成500个任务。

这500个任务可以是单进程/单线程方式处理的,这时表示的是并发不并行的模式(coroutine就是典型的并发不并行),

即先执行完一个任务后才执行另一个任务,也可以是多进程/多线程方式处理的,这时表示的是并发且并行模式。

要解决大并发问题,通常是将大任务分解成多个小任务

很典型的一个例子是处理客户端的请求任务,这个大任务里面包含了监听并建立客户端的连接、处理客户端的请求、响应客户端。但基本上所有这类程序,都将这3部分任务分开了:在执行任何一个小任务的时候,都可以通过一些手段使得可以执行其它小任务,比如在处理请求的时候,可以继续保持监听状态。

由于操作系统对进程的调度是随机的,所以切分成多个小任务后,可能会从任一小任务处执行。这可能会出现一些现象:

  • 可能出现一个小任务执行了多次,还没开始下个任务的情况。这时一般会采用队列或类似的数据结构来存放各个小任务的成果。比如负责监听的进程已经执行了多次,建立了多个连接,但是还没有调度到处理请求的进程去处理任何一个请求。

  • 可能出现还没准备好第一步就执行第二步的可能。这时,一般采用多路复用或异步的方式,比如只有准备好产生了事件通知才执行某个任务。比如还没有和任何一个客户端建立连接时,就去执行了处理请求的进程。

  • 可以多进程/多线程的方式并行执行这些小任务。也可以单进程/单线程执行这些小任务,这时很可能要配合多路复用才能达到较高的效率

总结

并行和串行:

  • 串行:一次只能取得一个任务并执行这一个任务
  • 并行:可以同时通过多进程/多线程的方式取得多个任务,并以多进程或多线程的方式同时执行这些任务
  • 注意点:
    • 如果是单进程/单线程的并行,那么效率比串行更差
    • 如果只有单核cpu,多进程并行并没有提高效率
    • 从任务队列上看,由于同时从队列中取得多个任务并执行,相当于将一个长任务队列变成了短队列

并发:

  • 并发是一种现象:同时运行多个程序或多个任务需要被处理的现象
  • 这些任务可能是并行执行的,也可能是串行执行的,和CPU核心数无关,是操作系统进程调度和CPU上下文切换达到的结果
  • 解决大并发的一个思路是将大任务分解成多个小任务:
    • 可能要使用一些数据结构来避免切分成多个小任务带来的问题
    • 可以多进程/多线程并行的方式去执行这些小任务达到高效率
    • 或者以单进程/单线程配合多路复用执行这些小任务来达到高效率

四,线程池

又以上介绍我们可以看出,在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。

而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是及其宝贵的,所以,我们就提出了线程池的概念。

线程池:Java中开辟出了一种管理线程的概念,这个概念叫做线程池。

从概念以及应用场景中,我们可以看出,线程池的好处,就是可以方便的管理线程,也可以减少内存的消耗。

那么,我们应该如何创建一个线程池?Java中已经提供了创建线程池的一个类:Executor

而我们创建时,一般使用它的子类:ThreadPoolExecutor.

public ThreadPoolExecutor(int corePoolSize,  int   maximumPoolSize,  long   keepAliveTime,  TimeUnit   unit,  BlockingQueue<Runnable>   workQueue,  ThreadFactory   threadFactory,  RejectedExecutionHandler   handler)

这是其中最重要的一个构造方法,这个方法决定了创建出来的线程池的各种属性,下面依靠一张图来更好的理解线程池和这几个参数:

图中,我们可以看出,线程池中的corePoolSize就是线程池中的核心线程数量,这几个核心线程,只是在没有用的时候,也不会被回收。

maximumPoolSize就是线程池中可以容纳的最大线程的数量,而keepAliveTime,就是线程池中除了核心线程之外的其他的最长可以保留的时间。

因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间,

而util,就是计算这个时间的一个单位,

workQueue,就是等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)。

threadFactory,就是创建线程的线程工厂,最后一个handler,是一种拒绝策略,我们可以在任务满了之后,拒绝执行某些任务。

线程池的执行流程又是怎样的呢?

我们可以看出,任务进来时,首先执行判断,判断核心线程是否处于空闲状态,

如果不是,核心线程就先就执行任务,

如果核心线程已满,则判断任务队列是否有地方存放该任务,

如果有,就将任务保存在任务队列中,等待执行,

如果满了,在判断最大可容纳的线程数,

如果没有超出这个数量,就开创非核心线程执行任务,

如果超出了,就调用handler实现拒绝策略。

handler的拒绝策略:

有四种:

第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满

第二种DisCardPolicy:不执行新任务,也不抛出异常

第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行

第四种CallerRunsPolicy:直接调用execute来执行当前任务

五,四种常见的线程池:

CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,

当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。

SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大

适用于执行周期性的任务。

SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。

FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程。

测试开发进阶——常用中间件概念——线程与线程池理解相关推荐

  1. 测试开发进阶——常用中间件概念——JMX监听器理解

    JMX的简介 JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架 ,从Java5.0开始引入到标准Java技术平台中. JMX是一套标准的代理和服务,实际 ...

  2. 测试开发进阶——常用中间件概念——JDBC——连接数据库理解

    Java MySQL 连接 本章节我们为大家介绍 Java 如何使用 使用 JDBC 连接 MySQL 数据库. Java 连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mys ...

  3. 测试开发 | 这些常用测试平台,你们公司在用的是哪些呢?

    测试管理平台是贯穿测试整个生命周期的工具集合,它主要解决的是测试过程中团队协作的问题.在整个测试过程中,需要对测试用例.Bug.代码.持续集成等等进行管理.下面分别从这四个方面介绍现在比较流行的管理平 ...

  4. web开发中常用的概念

    Tomcat服务器 Web开发中的常见概念 B/S系统和C/S系统 Brower/Server:浏览器 服务器 系统 ----- 网站 Client/Server:客户端 服务器 系统 ----- Q ...

  5. 测试开发面试(八)——进程与线程、python数据结构、数据库

    一.对公司有何了解? 星网锐捷是位于福州的国内领先的企业级网络.通讯.终端设备.视频应用产品及系统解决方案供应商,秉承的是"融合科技创新,构建智慧未来"的经营理念,公司旗下有多个子 ...

  6. 高级测试开发进阶知识详解

    一.软件测试工程师任职要求 1.技能要求 1)熟悉软件研发流程,即软件生命周期: 2)相关软件业务知识: 3)软件开发模型.测试模型: 4)常见测试方法:黑盒测试.白盒测试: 5)常见测试工具:LD. ...

  7. 测试开发进阶(四十四)

    运行一个页面 index.html <html lang="en"> <head><meta charset="UTF-8"> ...

  8. 霍格沃兹测试开发进阶班16期

    内容不重要,[看我名字]你明白我的意思最重要! 先抛出我的结论: 之所以很多人会认为自动化测试很厉害,原因在于国内IT行业对于coding的崇拜,更是源于国内测试人员自身coding能力普遍不足导致的 ...

  9. 测试开发进阶——APP性能监测工具——itest

  10. 软件测试 | 测试开发 | 年薪超过40W,一位测试媛宝妈的 BAT 大厂逆袭之旅

    本文为霍格沃兹测试学社优秀学员跳槽笔记,测试开发进阶学习文末加群. 本人之前是在一家二流互联网企业(已上市,不算真正的互联网),工作2年多.因为业务不断的调整和结婚生孩子,导致绩效不佳还是刚入职时的薪 ...

最新文章

  1. overflow超出显示_[CSS]text-overflow: ellipsis;什么时候可能不生效?
  2. 华为q1设置虚拟服务器,如何使用华为华为Q1 Q1互联网路由设置图文教程 | 192.168.1.1手机登陆...
  3. c语言变凉存储性,C语言数据的表示和存储(IEEE 754标准)
  4. 以后再也不去字节面试了…
  5. 每日一题之 MySQL
  6. win10没有windows无线服务器,win10系统电脑没windows无线服务的解决方法
  7. leetcode 4 --- 寻找两个有序数组的中位数
  8. 软件测试 学习之路 Linux基础命令 (一)
  9. Java实训项目10:GUI学生信息管理系统 - 实现步骤 - 创建数据访问接口实现类
  10. (转)增强学习(二)----- 马尔可夫决策过程MDP
  11. 解决ppt复制到Word的图片导出PDF后出现黑线问题,word转PDF图片不清晰的问题,ppt转矢量图问题
  12. GetLastError 错误代码
  13. 如何选择适合你的兴趣爱好(二十八),小提琴
  14. MC(monitorcat) 监控军刀
  15. Nebula3 资源管理系统
  16. 电脑重启bootmgr_电脑出现bootmgr is missing怎么办
  17. 使用ADO创建Excel数据表
  18. 浅谈学习编程语言的心得与体会
  19. centos 拨号上网
  20. sap 获取计划订单bapi_【原创】2011.09.18 SAP 订单中修改订单净价

热门文章

  1. 思迅商云8版的最后一个版本_泪目!科比成为2K21第3位封面球星,将推出曼巴永恒版...
  2. 深入Unreal蓝图开发:实现蓝图模板函数
  3. Neo4j 构建简单农业知识图谱(Agriculture KnowledgeGraph)
  4. 【前端初/中级面经】中小型公司面试时都会问些什么,VUE出境最高?
  5. 工具系列 | FPM进程管理器详解
  6. 414.Fizz Buzz
  7. sin的傅里叶变换公式_正弦信号傅里叶变换
  8. 万维网联盟:已完成对HTML5的规范开发
  9. Word毕业论文排版 公式居中 编号右对齐 及交叉引用(使用MathType公式编辑器实现)
  10. 做网站推广最实用的88种网站推广方法