Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >线程与Java线程

线程与Java线程

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

对于程序的运行过程,操作系统中最重要的两个概念是进程和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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java 多线程 Thread 和 Runnable
多线程是并行计算实现的方式, 但是在单cpu中实际上没有真正的并行,只不过是多个任务通过cpu的快速轮转,产生多任务同一时间运行的错觉.而其中的任务就是进程. (当然多核CPU,并行还是真实存在的). 一个进程中至少有一个线程,线程运行在进程中,但是cpu的调度的是进程中的线程,所以一个线程可以占据多个cpu核.
Tim在路上
2020/08/04
5610
Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)
在Thread类中有内部类 枚举State,用于抽象描述Java线程的状态,共有6种不同的状态
noteless
2019/03/04
9020
Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)
Java线程生命周期与状态切换
最近有点懒散,没什么比较有深度的产出。刚好想重新研读一下JUC线程池的源码实现,在此之前先深入了解一下Java中的线程实现,包括线程的生命周期、状态切换以及线程的上下文切换等等。编写本文的时候,使用的JDK版本是11。
Throwable
2020/06/23
8780
Java线程的几种状态
java.lang.Thread.State中定义的集中Java线程的状态: 1 /** 2 * A thread state. A thread can be in one of the following states: 3 * <ul> 4 * <li>{@link #NEW}<br> 5 * A thread that has not yet started is in this state. 6 * </li> 7 * <li>{@link
欠扁的小篮子
2018/04/10
1.4K0
Java线程的几种状态
【Java并发系列】Java线程基础
线程的runnable状态是从虚拟机的角度来看的,表示这个线程正在运行。但是处于Runnable状态的线程不一定真地消耗CPU。处于Runnable的线程只能说明该线程没有阻塞在java的wait或者sleep方法上,同时也没等待在锁上面。但是如果该线程调用了本地方法,而本地方法处于等待状态,这个时候虚拟机是不知道本地代码中发生了什么,此时尽管当前线程实际上也是阻塞的状态,但实际上显示出来的还是runnable状态,这种情况下是不消耗CPU的。
章鱼carl
2022/03/31
2740
【Java并发系列】Java线程基础
Java基础16:Java多线程基础最全总结
本文介绍了Java多线程的基本概念,使用方法,以及底层实现原理。帮助你更好地使用Java的多线程。
程序员黄小斜
2019/04/07
8340
Java多线程与并发
答:进程是资源分配的最小单位,线程是CPU调度的最小单位。   1)、进程是资源分配的基本单位,所有与进行相关的资源,都被记录在进程控制块PCB中,以表示该进程拥有这些资源或者正在使用它们。   2)、进程是抢占处理机的调度单位,线程属于某个进程,共享其资源。进程拥有一个完整的虚拟内存地址空间,当进程发生调度的时候,不同的进程拥有不同的虚拟地址空间,而同一进程内不同线程共享同一地址空间,与进程相对应。线程与资源分配无关,它属于某一个进程,并与进程内的其它线程一起共享进程里面的资源。   3)、线程只由堆栈、寄存器、程序计数器和线程计数表TCB组成。
别先生
2020/04/10
1.1K0
Java多线程与并发
面试官:为什么Java线程没有Running状态?
Java虚拟机层面所暴露给我们的状态,与操作系统底层的线程状态是两个不同层面的事。具体而言,这里说的 Java 线程状态均来自于 Thread 类下的 State 这一内部枚举类中所定义的状态:
田维常
2019/10/31
3770
Java线程为何没有Running状态?我猜你不知道。
Java虚拟机层面所暴露给我们的状态,与操作系统底层的线程状态是两个不同层面的事。具体而言,这里说的 Java 线程状态均来自于 Thread 类下的 State 这一内部枚举类中所定义的状态:
Bug开发工程师
2019/08/13
3990
Java线程为何没有Running状态?我猜你不知道。
线程生命周期,五大状态转换分析
本章学习完成,你将会对线程的生命周期有清楚的认识,并且明白不同状态之间是如何转换的,以及对java线程状态枚举类解读。
公众号 IT老哥
2020/09/16
5710
线程生命周期,五大状态转换分析
并发多线程学习(五)Java线程的状态及主要转化方法
处于NEW状态的线程此时尚未启动。这里的尚未启动指的是还没调用Thread实例的start()方法。
用户10168815
2023/02/28
3020
并发多线程学习(五)Java线程的状态及主要转化方法
【Java学习笔记之三十四】超详解Java多线程基础
前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧。 正文 线程与进程 1 线程:进程中负责程序执行的执行单元 线程本身依靠程序进行运行 线程是程序中的顺序控制流,只能使用分配给程序的资源和环境 2 进程:执行中的程序 一个进程至少包含一个线程 3 单线程:程序中只存在一个线程,实际上主方法就是一个主线程 4 多线程:在一个程序中运行多个任务 目的是更好地使用CPU资源 线程的实现 继承Thread类
Angel_Kitty
2018/04/09
9210
【Java学习笔记之三十四】超详解Java多线程基础
相关推荐
Java 多线程 Thread 和 Runnable
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档