Java多线程模型

谈到Java多线程就涉及到多线程的模型及Java线程与底层操作系统之间的关系。正如我们熟知,现代机器可以分为硬件和软件两大块,如图2-5-1-1,硬件是基础,软件提供实现不同功能的手段。而且软件可以分为操作系统和应用程序,操作系统专注于对硬件的交互管理并提供一个运行环境给应用程序使用,应用程序则是能实现若干功能的并且运行在操作系统环境中的软件。同样,线程按照操作系统和应用程序两层次可以分为内核线程(Kernel Thread)和用户线程(User Thread)。
 
图2-5-1-1
所谓内核线程就是直接由操作系统内核支持和管理的线程,线程的建立、启动、同步、销毁、切换等操作都由内核完成。基本所有的现代操作系统都支持内核线程。用户线程指完全建立在用户空间的线程库上,由内核支持而无需内核管理,内核也无法感知用户线程的存在,线程的建立、启动、同步、销毁、切换完全在用户态完成,无需切换到内核。可以把用户线程看成是更高层面的线程,而内核线程则是最底层的支持,那么他们之间必然存在一定的映射关系,一般有三种常用的关系,下面将逐个列出。
① 一对一模型
一对一模型可以说是最简单的映射模型,如图2-5-1-2,KT为内核线程,UT为用户线程,每个用户线程都对应一个内核线程,由于每个用户线程都有各自的内核线程,所以他们互不影响,即使其中一个线程阻塞,也允许另一个线程继续执行,这无疑是此模型的优点,但也存在一个严重的缺陷,由于一对一的关系,有多少个用户线程就代表有多少个内核线程,而内核线程的开销较大,一般操作系统都会有内核线程数量的限制,用户线程的数量也被限制。
 
图2-5-1-2
② 多对一模型
第二种是多对一模型,如图2-5-1-3,可以清晰看到多个用户线程映射到同一个内核线程上,可以看成由一条内核线程实现若干个用户线程的并发功能,线程的管理在用户空间中进行,一般不需要切换到内核态,效率较高,而且比起一对一模型,支持的线程数量更大。但此模型有个致命的弱点是如果一个线程执行了阻塞调用,所有线程都将阻塞,并且任意时刻只能有一个线程访问内核。另外,对线程的所有操作都将由用户应用自己处理。所以一般除了在不支持多线程的操作系统被迫使用此模型外,在多线程操作系统中基本不使用。
 
图2-5-1-3
③ 多对多模型
多对多模型的提出是为了解决前面两种模型的缺点,如图2-5-1-4,多个用户线程与多个内核线程映射形成多路复用。前面提到的一对一模型存在受内核线程数量限制的问题,多对一模型虽然解决了数量限制问题,但它存在一个线程阻塞导致所有线程阻塞的风险,而且由于一个内核线程只能调度一个线程导致并发性不强。看看多对多模型如何解决这些问题,由于多对一是多对多的子集,所以多对多具备多对一的优点,线程数不受限制。除此之外,多个内核线程可处理多个用户线程,当某个线程阻塞时,将可以调度另外一个线程执行,这从另一方面看也是增强了并发性。
 
图2-5-1-4

三种模型各自有各自的特点,不同的现代操作系统可能使用不同的线程模型,例如linux和windows可能使用了一对一模型,而solaris和unix某些版本可能使用多对多模型。对于线程的创建和管理主要由线程库提供用户级别和内核级别两种API进行操作。用户级别由于不涉及内核操作,所有代码和数据结构均存放在用户空间,与此相反,内核级别由内核支持,将直接调用内核系统操作,代码和数据结构存在与内核空间中。在实际程序中我们一般不直接使用内核线程,用户线程与内核线程直接需要一种中间数据结构,它由内核支持且是内核线程的高级抽象,这个高级接口被称为轻量级进程(Light Weight Process),下面简称LWP。图2-5-1-5是三种模型增加了轻量级进程的示意图,从某种层面上看,LWP最多算是广义的用户线程,并非狭义定义的用户进程,LWP线程库是以内核为基础,很多操作要进行内核调用,效率不高,如果要快速低消耗的操作则需要一个纯粹的用户线程,线程库完全建立在用户空间。于是可以看到一个进程P里面一般包含若干个用户进程,用户进程以某种关系对应轻量级进程,而轻量级进程则是内核线程的高级体现。如此一来,一个内核线程堵塞将导致LWP也阻塞,与LWP相连的用户线程也将阻塞。


图2-5-1-5

最后要谈谈Java线程与底层操作系统的关系,由于Java通过JVM封装了底层操作系统的差异,所以Java线程也必然是要封装不同操作系统提供一个统一的并发定义,在JDK发展历史上,java语言开发者曾经通过一类叫“绿色线程(Green Threads)”的用户线程进行实现Java线程,但从jdk1.2开始,java线程使用操作系统原生线程模型实现,也就是说Java线程的实现通过不同操作系统提供的线程库分别实现,JVM根据不同操作系统的线程模型对Java线程进行映射,假如Java运行在windows系统上,它通常直接使用Win32 API实现多线程,假如Java运行在linux系统则直接使用Pthread线程库实现多线程。这样一来就顺利隐藏了底层实现细节,提供给开发者就是一个具有统一抽象的线程语义。

点击订购作者书籍《Tomcat内核设计剖析》

时间: 2024-09-22 19:04:36

Java多线程模型的相关文章

Java 并发/多线程教程(十一)-JAVA内存模型

本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获.由于个人水平有限,不对之处还望矫正!         Java内存模型指定Java虚拟机如何与计算机的内存(RAM)一起工作.Java虚拟机是整个计算机的一个模型,所以这个模型自然包含了一个内存模型--也就是Java内存模型.         如果您想要设计正确的并发程序,那么理解Java内存模型是非常重要的.Java内存模型指定了不同线程如何以及何时可以看到由其他线程写入共享变量的值,以及在必要时如何同步访问共享变量

多线程并发之java内存模型JMM

多线程概念的引入是人类又一次有效压寨计算机的体现,而且这也是非常有必要的,因为一般运算过程中涉及到数据的读取,例如从磁盘.其他系统.数据库等,CPU的运算速度与数据读取速度有一个严重的不平衡,期间如果按一条线程执行将会在很多节点产生阻塞,使计算效率低下.另外,服务器端是java最擅长的领域,作为服务器必须要能同时响应多个客户端的请求,同样需要多线程的支持.在多线程情况下,高并发将带来数据的共享与竞争问题,tomcat作为中间件将多线程并发等细节尽量封装起来处理,使用户对多线程透明,更多地关注业务

jsp 多线程开发与Java并发模型框架

基础知识 Java语言提供了对于线程很好的支持,实现方法小巧.优雅.对于方法重入的保护,信号量(semaphore)和临界区(critical section)机制的实现都非常简洁.可以很容易的实现多线程间的同步操作从而保护关键数据的一致性.这些特点使得Java成为面向对象语言中对于多线程特性支持方面的佼佼者(C++正在试图把boost库中的对于线程的支持部分纳入语言标准). Java中内置了对于对象并发访问的支持,每一个对象都有一个监视器(monitor),同时只允许一个线程持有监视器从而进行

Java线程模型缺陷研究

Java 编程语言的线程模型可能是此语言中最薄弱的部分.它完全不适合实际复杂程序的要求,而且也完全不是面向对象的.本文建议对 Java 语言进行重大修改和补充,以解决这些问题. Java 语言的线程模型是此语言的一个最难另人满意的部分.尽管 Java 语言本身就支持线程编程是件好事,但是它对线程的语法和类包的支持太少,只能适用于极小型的应用环境. 关于 Java 线程编程的大多数书籍都长篇累牍地指出了 Java 线程模型的缺陷,并提供了解决这些问题的急救包(Band-Aid/邦迪创可贴)类库.我

深入理解Java内存模型(三) 顺序一致性

数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数 据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序. 当代码中包含数据竞争时,程序的执行往往产生违反直觉的结果(前一章的示例正是如此).如果一 个多线程程序能正确同步,这个程序将是一个没有数据竞争的程序. JMM对正确同步的多线程程序 的内存一致性做了如下保证: 如果程序是正确同步的,程序的执行将具有顺序一致性(sequentially consisten

深入理解Java内存模型(一) 基础

并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之 间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令 式编程中,线程之间的通信机制有两种:共享内存和消息传递. 在共享内存的并发模型里,线程 之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.在消息传递的并发模 型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信. 同步是指程 序用于控制不同线程之间操作发生相对顺序的机制.在共

Java多线程编程实战之基础

在 Java 程序中使用多线程要比在 C 或 C++ 中容易得多,这是因为 Java 编程语言提供了语言级的支持.本文通过简单的编程示例来说明 Java 程序中的多线程是多么直观.读完本文以后,用户应该能够编写简单的多线程程序. 为什么会排队等待? 下面的这个简单的 Java 程序完成四项不相关的任务.这样的程序有单个控制线程,控制在这四个任务之间线性地移动.此外,因为所需的资源 - 打印机.磁盘.数据库和显示屏 -- 由于硬件和软件的限制都有内在的潜伏时间,所以每项任务都包含明显的等待时间.因

Java多线程编程实战之限制优先级

限制线程优先级和调度 Java 线程模型涉及可以动态更改的线程优先级.本质上,线程的优先级是从 1 到 10 之间的一个数字,数字越大表明任务越紧急.JVM 标准首先调用优先级较高的线程,然后才调用优先级较低的线程.但是,该标准对具有相同优先级的线程的处理是随机的.如何处理这些线程取决于基层的操作系统策略.在某些情况下,优先级相同的线程分时运行:在另一些情况下,线程将一直运行到结束.请记住,Java 支持 10 个优先级,基层操作系统支持的优先级可能要少得多,这样会造成一些混乱.因此,只能将优先

实战Java多线程编程精要之限制优先级

限制线程优先级和调度 Java 线程模型涉及可以动态更改的线程优先级.本质上,线程的优先级是从 1 到 10 之间的一个数字,数字越大表明任务越紧急.JVM 标准首先调用优先级较高的线程,然后才调用优先级较低的线程.但是,该标准对具有相同优先级的线程的处理是随机的.如何处理这些线程取决于基层的操作系统策略.在某些情况下,优先级相同的线程分时运行:在另一些情况下,线程将一直运行到结束.请记住,Java 支持 10 个优先级,基层操作系统支持的优先级可能要少得多,这样会造成一些混乱.因此,只能将优先