前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程与Java线程

线程与Java线程

作者头像
搬砖俱乐部
发布2019-06-15 17:32:49
1.7K0
发布2019-06-15 17:32:49
举报
文章被收录于专栏:BanzClub

对于程序的运行过程,操作系统中最重要的两个概念是进程和CPU,进程就是运行程序的一个抽象,CPU主要工作就是对进程的调度。需要理解的是,一个CPU在一个瞬间,只能执行一个进程,通常这个时间片段是几十毫秒或几百毫秒,但对于用户来讲,就像多个程序同时运行,这就是伪并行(对于一个CPU来讲)。进程包含几乎程序运行的所需要的所有信息,包括程序计数器、堆栈指针、程序对应地址空间(存放可执行程序、程序的数据、程序的堆栈等)的读写操作以及其他资源的信息。进程的执行有三个状态:正在运行的进程是运行态,还包括就绪态(可运行,CPU正在执行别的进程)、阻塞态(等待某个资源或某个事件发生之前的进程的状态)。三种状态的切换如下图所示:

为了实现进程模型,操作系统维护着一张表格,即进程表。每个进程占用一个进程表项。该表项包含了进程状态的重要信息,如下图:

在了解进程表之后,还需要理解中断的概念:对于进程来说,中断意味着进程需要让出CPU,进程进入阻塞状态,需要在进程表项中保存进程相关信息,以便下次CPU执行时,可以继续执行进程;对于磁盘来说,中断是指磁盘完成了程序指定的响应的任务,产生的中断信号;对于CPU来说,在就绪队列中,轮询到下一个进程时间片时,从中断向量中读取到寄存器信息,将会继续执行该进程。

那什么是线程呢?为什么有了进程还需要线程呢?

首先,考虑程序的功能,往往不是单一的功能,比如在执行一件事的同时,可以进行其他事情,这时一方面,进程的创建相比于线程的创建来说,比较消耗资源,也就是线程更加轻量级;另一方面,线程可以共享地址空间,这对于一些应用程序来说,确实是比较需要的。然后,如果CPU密集型的任务,涉及到CPU的计算和上下文切换,多线程的处理能力,可能并不会比多进程有太大的优势,但对于I/O密集型的任务来说,而随着多核计算机的普及,硬件领先软件的情景出现,使得并行处理有了发展硬件支撑,所以多线程技术也得到了很好的发展。当然,线程也有缺点,由于一个线程死掉了意味着整个进程就死掉了,而一个进程死掉不会影响其他进程,所以多线程应用相对于进程应用来说,没有其表现的稳定。

线程包含各自的程序计数器、局部变量、堆栈以及对对共享空间的访问。

线程的生命周期包含5种类型(同进程一致):

  • NEW(新建):非系统中真实存在的线程状态
  • RUNNABLE(就绪):
  • RUNNING(运行):
  • BLOCKED(阻塞):
  • TERMINATED(终止):非系统中真实存在的线程状态

线程间的状态切换如下图所示:

操作系统线程的实现有3种方式:使用内核线程实现,使用用户线程实现,使用用户线程加轻量级进程混合实现。

Java线程是JVM进程的线程,由于多核系统的普及,充分发挥多核系统的调度优势,JVM较新版本所支持的所有平台上,大部分采用的是内核实现方式的线程模型。即通过轻量级进程接口(LWP)调用系统的内核线程KLT,再通过操作系统的调度器进行线程的分配执行。

Java线程的在JVM内存结构中包括私有空间和共有空间,也就是Java虚拟机的内存模型。根据虚拟机规范,Java线程私有的空间包括程序计数器,存放当前线程接下来要执行的字节码指令、分支、循环、跳转、异常处理等;Java虚拟机栈,生命周期与线程相同,在方法执行时都需要创建栈帧的数据结构,存放局部变量表、操作栈、动态链接、方法出口等,虚拟机栈大小通过-xss参数配置;本地方法栈,专门用来存储JNI方法的内存区域。Java线程共有的空间包括堆内存,用于存储Java运行时期创建的对象,垃圾回收大部分发生在此区域,堆内存还分新生代(Eden区、From Survivor区、To Survivor区)和老年代;方法区,主要存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码等,在1.7版本JVM使用的是永久代,在1.8使用的是元空间来实现方法区。

在JDK中代表线程的是Thread类,Java Thread定义了线程名、线程ID、优先级、是否守护线程、执行目标、线程组、线程状态等属性。而Runnable接口是线程类的执行目标,通过模板设计模式将执行目标的run方法,封装到了线程Thread的start中。所以线程执行的方法是start(),而不是run()。由Thread类创建的对象都会一一映射到操作系统中的OSThread,Thread类通过一系列native方法(JNI)来进行线程的操作。

线程操作

线程sleep:当前线程进入指定时间的休眠(注:具体休眠时间以系统的调度的精度为准);

线程yield:主动放弃当前的CPU资源(有可能被CPU忽略),状态由Running->Runnable;

线程interrupt:打断进入阻塞状态(调用wait、sleep、join等)的线程,只是阻塞状态被打断,不等于结束线程的生命周期。

线程join:在线程A中,线程B调用join方法(可带时间参数),会使线程A进入等待,直到线程A结束生命周期或者超过指定的时间参数,在此期间线程B处于BLOCKED状态。

线程关闭:stop方法(已过期,不建议使用);正常关闭(线程结束生命周期正常结束;捕获中断信号关闭线程;使用volatile变量控制线程关闭);异常关闭(通过抛出异常退出线程;进程假死-线程阻塞或者死锁导致)

线程wait/notify/notifyAll:wait方法使线程进入等待状态,由Runnable变成Waiting;notify/notifyAll方法唤醒等待状态的线程。线程的sleep和wait看起来都是让线程进入等待状态,不过二者是有区别的,线程sleep之后,不会释放调monitor对象锁,只有当线程执行完成之后,其他线程才可以重新进入,而线程wait之后,当前线程会释放调monitor对象锁,其他线程可以进入同步块,线程唤醒之后再重新竞争锁。典型的wait/notify机制,比较适合生产者和消费者模式,如下所示:

在经典的生产、消费模型里,当线程在wait方法,被唤醒之后,不是直接进入Runnable转态,而是先进入阻塞队列,进行等待锁,也就是Blocked,获得锁之后才能进入Runnable状态。

线程状态

Java线程状态包括New(初始)、Runnable(运行状态-包含就绪和运行中)、Blocked(阻塞,阻塞于锁)、Waiting(等待,等待其他线程的动作-通知或中断)、Time_Waiting(超时等待)、Terminated(终止)。

线程调度

线程调度就是为某个线程分配CPU的使用权的过程,这个过程一般分为抢占式调度和协同式调度。Java线程属于抢占式调度,每个线程都会分同样的执行时间片,每次执行时候涉及到上下文切换。在JVM规范中规定每个线程都有优先级,优先级高优先执行,同样优先级则随机选择执行,但实际情况中,这并不是绝对的,所以不能严格按照优先级顺序编写逻辑。

线程数量

线程数量主要受到JVM虚拟机的配置和系统限制所影响:

  • JVM虚拟机配置
    • 堆内存
    • 栈空间
  • 系统限制
    • /proc/sys/kernel/threads-max
    • /proc/sys/kernel/pid_max
    • /proc/sys/vm/max_map_count
    • max_user_process(ulimit -u)

一般线程数量的计算公式:

  • 线程数量 =(最大地址空间(MaxProcessMemory) - JVM堆内存 - ReservedOsMemory(系统保留内存))/ThreadStackSize(Xss)
  • 线程数量 = 内核数量 / (1 - 堵塞率)

  1. 《Java并发编程的艺术》
  2. 《Java并发编程实战》
  3. 《现代操作系统-第四版》
  4. 《深入理解Java虚拟机》
  5. http://www.cnblogs.com/llguanli/p/7095457.html
  6. https://blog.csdn.net/yangmx_5/article/details/68065299
  7. https://blog.csdn.net/CringKong/article/details/79994511
  8. https://blog.csdn.net/ns_code/article/details/17225469
  9. https://www.zhihu.com/question/23096638
  10. https://juejin.im/post/5aea581ff265da0b82629c76
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BanzClub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程操作
  • 线程状态
  • 线程调度
  • 线程数量
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档