Java多线程的内存模型和Thread状态切换
线程的内存模型
32位操作系统的寻址空间为2的32次方,也就是4GB的寻址空间;系统在这4GB的空间里划分出1GB的空间给系统专用,称作内核空间,具有最高权限;剩下3GB的空间为用户空间(一般JVM的可用内存最大只能是2GB),只能访问当前线程划分的内存地址。用户线程需要访问硬件资源的时候需要委托内核线程进行访问,这就涉及到CPU上下文在用户模式和内核模式的切换。因此在使用线程或者进程的时候需要尽量避免不必要的用户模式和内核模式的切换。
进程是资源管理的最小单位,线程是CPU调度的最小单位。线程是比进程更轻量级的调度执行单位,线程可以共享同一个进程内的资源(内存地址、文件I/O等),又是CPI独立调度的基本单位。主要有三种实现线程的方法:
#1 使用一个内核线程支持一个用户进程,并且用户进程内支持多线程,优势在于线程的切换都发生在用户模式,劣势在于线程对于系统内核而言完全是透明的,所有资源调度需要用户进程进行处理,并且由于只有一个内核线程,所以只有一个CPU资源可以使用(多核CPU完全排不上用场),如果一个硬件I/O操作阻塞,所以的线程的硬件I/O都被阻塞。
#2 使用内核线程(Kernel Level Thread)一对一支持轻量级进程(Light Weight Process),一个轻量级进程对应一个线程,优势在于可以最大利用多CPU的性能,多任务同时进行,但最大劣势在于由于线程的阻塞或者唤醒都需要系统内核进行处理,所以程序需要不断在用户模式和内核模式之间切换,增加切换成本。
#3使用内核线程(Kernel Level Thread)一对一支持轻量级进程(Light Weight Process),并使用轻量级进程多对多支持用户线程,也就是混合使用前面两种实现的优势。这样上下文切换主要发生在用户模式,并且又可以依赖内核线程直接调用系统内核的功能。

线程的状态切换
Java多线程主要涉及到两种数据访问的同步,一种是heap中多线程可见的实例变量,一种是method area中的类成员变量,而method call stack中的数据是线程私有,则不需要进行同步协调。线程对象调用start方法之后就进入Ready状态等待线程调度器分配CPU资源进入Running,然后因为三种原因线程可能进入waiting/blocked状态:调用sleep/wait/suspend/join方法,调用了阻塞式IO方法,等待获取锁。

线程的Java编程接口
JDK自带开发包中支持两种线程的实现方式,extends Thread和implements Runnable,两种方式都是通过重写run()方法实现线程操作,唯一的区别在于前者限制了当前类不能再有其他业务上的继承父类。
public class App1 extends Thread {
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread().getName() + " : start");
}
public static void main(String[] args) {
App1 thread = new App1();
thread.setName("App1 Thread");
thread.start();
System.out.println(Thread.currentThread().getName() + " : start");
}
}
public class App1 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : start");
}
public static void main(String[] args) {
Thread app1Thread = new Thread(new App1());
app1Thread.setName("App1 Thread");
app1Thread.start();
System.out.println(Thread.currentThread().getName() + " : start");
}
}
线程的启动方式:
#1 调用Thread.start()为异步实现,表示通知线程规划器指定的线程已经就绪,等待分配CPU资源并调用重写的run()方法,因此线程的执行具有不确定性;
#2 调用Thread.run()为同步实现,将不会获取任何线程相关的特性,而是简单的方法调用。
线程的退出方式:
#1 Thread.run()执行结束后线程正常退出。
#2 使用Thread.stop()强制退出(不推荐)
#3 使用Thread.interrupt()向线程发送需要结束的信号,但并不能立即停止线程,线程代码中需要调用Thread.interrupted()(或者是一个自定义的标志位)判断当前线程是否需要结束,从而手动控制线程的执行状态。
线程的优先级
通过Thread.setPriority(val)方法可以设置线程优先级,范围从1到10,线程调度器会将CPU资源尽量分给具有高优先级的线程,但并不意味着优先级高的线程总是能优先获取CPU资源;优先级具有继承性,子线程具有跟父线程同样的优先级。
死锁的产生和避免
Thread.suspend()和不指定超时时间的Object.wait()最容易产生死锁。利用JDK自带的工具jps可以监测线程是否已经进入死锁状态($ jps -l PID)。
Java多线程的内存模型和Thread状态切换的更多相关文章
- 【Java】JMM内存模型和JVM内存结构
JMM内存模型和JVM内存结构 JAVA内存模型(Java Memory Model) Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由JSR-133: JavaTM Memor ...
- Java多线程系列1 线程创建以及状态切换
我们知道线程线程有三种创建方式 1实现Runnable接口 2 继承Thread类 3使用Callable和Future接口创建线程.具体是创建Callable接口的实现类,并实现clall()方法. ...
- 黑马-----内存模型和volatile详解
黑马程序员:Java培训.Android培训.iOS培训..Net培训 JAVA线程-内存模型和volatile详解 一.单核内存模型 1.程序运行时,将临时数据存放到Cache中 2.将CPU计算所 ...
- Java内存模型和JVM内存管理
Java内存模型和JVM内存管理 一.Java内存模型: 1.主内存和工作内存(即是本地内存): Java内存模型的主要目标是定义程序中各个变量的访问规则,即在JVM中将变量存储到内存和从内存中取 ...
- 并发一:Java内存模型和Volatile
并发一:Java内存模型和Volatile 一.Java内存模型(JMM) Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和在内存中取出变量的底层细节,是围绕着 ...
- JVM内存结构、Java内存模型和Java对象模型
Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚.比如本文要讨论的JVM内存结构.Java内存模型和Java对象模型 ...
- Java 内存模型和 JVM 内存结构真不是一回事
这两个概念估计有不少人会混淆,它们都可以说是 JVM 规范的一部分,但真不是一回事!它们描述和解决的是不同问题,简单来说, Java 内存模型,描述的是多线程允许的行为 JVM 内存结构,描述的是线程 ...
- JAVA内存模型和Happens-Before规则
前言 上一篇文章王子给大家介绍了并发编程中比较关心的三个核心问题,可见性.有序性和原子性. 今天我们继续来探索并发编程的内容,聊一聊JAVA的内存模型和Happens-Before规则. JAVA内存 ...
- java多线程03-----------------volatile内存语义
java多线程02-----------------volatile内存语义 volatile关键字是java虚拟机提供的最轻量级额的同步机制.由于volatile关键字与java内存模型相关,因此, ...
随机推荐
- Android Studio新建类头部注释和添加函数注释模板及快捷键
一,Android Studio新建类头部注释 是不是有时候看到这个很心烦 其实Studio中有设置修改这些注释模板的信息的功能 其实很简单,只需要两步: 1.打开Setting设置面板,找到File ...
- 莫队初探(不带修/例题极少)By cellur925
因为今天考到莫队裸题了嘤嘤嘤...而我这样的蒟蒻肯定不会这样的高端算法啊QAQ.于是暴力水了40分qwq. 正如上文所说,我实在太菜了,于是学习莫队也只是学习了最简单的不带修普通莫队,如果我能苟到省选 ...
- Ubuntu解决中文乱码
gsettings set org.gnome.gedit.preferences.encodings candidate-encodings "['GB18030', 'UTF-8', ' ...
- 【转】有了Auto Layout,为什么你还是害怕写UITabelView的自适应布局?
Apple 算是最重视应用开发体验的公司了.从Xib到StoryBoard,从Auto Layout到Size Class,每一次的更新,都会给iOS应用的开发带来不小的便利.但是,对于绝对多数i ...
- mybaits 连接数据库汉字保存乱码??
查看数据库连接地址: jdbc.url=jdbc:mysql://localhost:3306/az?useUnicode=true&characterEncoding=utf-8 多了一个a ...
- ultraedit 窗口布局
回复默认的设置:工具栏中的视图-->环境-->左边小框里选择“编程员”,再点选择环境 改变使UltraEdit有多个窗口出来 视图’——‘视图/列表’——‘打开文件标签
- jQuery中的.html()和.text()及.val()区别
https://www.cnblogs.com/zhang-xun/p/6766264.html
- IOCP编程之基本原理
在我的博客之前写了很多关于IOCP的“行云流水”似的看了让人发狂的文章,尤其是几篇关于IOCP加线程池文章,更是让一些功力不够深厚的初学IOCP者,有种吐血的感觉.为了让大家能够立刻提升内力修为,并且 ...
- UvaLive6439(string使用、回文串)
样例手写一写很容易发现规律(前后一样的串,则ans+=2),实现起来却忘了string的便捷性,其实根本用不到哈希. ; int n, ans; string s, t1, t2; int main( ...
- Kruskal && Prim模板
1. Kruskal(并查集模板): /* Kruskal:并查集实现,记录两点和距离,按距离升序排序,O (ElogE) */ struct Edge { int u, v, w; bool ope ...