线程的内存模型

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状态切换的更多相关文章

  1. 【Java】JMM内存模型和JVM内存结构

    JMM内存模型和JVM内存结构 JAVA内存模型(Java Memory Model) Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由JSR-133: JavaTM Memor ...

  2. Java多线程系列1 线程创建以及状态切换

    我们知道线程线程有三种创建方式 1实现Runnable接口 2 继承Thread类 3使用Callable和Future接口创建线程.具体是创建Callable接口的实现类,并实现clall()方法. ...

  3. 黑马-----内存模型和volatile详解

    黑马程序员:Java培训.Android培训.iOS培训..Net培训 JAVA线程-内存模型和volatile详解 一.单核内存模型 1.程序运行时,将临时数据存放到Cache中 2.将CPU计算所 ...

  4. Java内存模型和JVM内存管理

    Java内存模型和JVM内存管理   一.Java内存模型: 1.主内存和工作内存(即是本地内存): Java内存模型的主要目标是定义程序中各个变量的访问规则,即在JVM中将变量存储到内存和从内存中取 ...

  5. 并发一:Java内存模型和Volatile

    并发一:Java内存模型和Volatile 一.Java内存模型(JMM) Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和在内存中取出变量的底层细节,是围绕着 ...

  6. JVM内存结构、Java内存模型和Java对象模型

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚.比如本文要讨论的JVM内存结构.Java内存模型和Java对象模型 ...

  7. Java 内存模型和 JVM 内存结构真不是一回事

    这两个概念估计有不少人会混淆,它们都可以说是 JVM 规范的一部分,但真不是一回事!它们描述和解决的是不同问题,简单来说, Java 内存模型,描述的是多线程允许的行为 JVM 内存结构,描述的是线程 ...

  8. JAVA内存模型和Happens-Before规则

    前言 上一篇文章王子给大家介绍了并发编程中比较关心的三个核心问题,可见性.有序性和原子性. 今天我们继续来探索并发编程的内容,聊一聊JAVA的内存模型和Happens-Before规则. JAVA内存 ...

  9. java多线程03-----------------volatile内存语义

    java多线程02-----------------volatile内存语义 volatile关键字是java虚拟机提供的最轻量级额的同步机制.由于volatile关键字与java内存模型相关,因此, ...

随机推荐

  1. 解决 CentOS 7 添加用户设置家目录出现 useradd cannot set SELinux context for home directory 问题

    问题描述 直接贴下代码吧~ [root@localhost ~]# useradd -d /tmp/heheda4 heheda4 useradd: cannot set SELinux contex ...

  2. TensorFlow多线程输入数据处理框架(四)——输入数据处理框架

    参考书 <TensorFlow:实战Google深度学习框架>(第2版) 输入数据处理的整个流程. #!/usr/bin/env python # -*- coding: UTF-8 -* ...

  3. 找不到javax.servlet.Filter的类文件

    在这里我是用IDEA来开发的,Tomcat用的maven插件 原因:没有相应在jar包 解决:导入相应在jar的依赖,在pom文件中添加 <dependency> <groupId& ...

  4. Hive导入10G数据的测试

    Hive导入10G数据的测试 让Hadoop跑在云端系列文章,介绍了如何整合虚拟化和Hadoop,让Hadoop集群跑在VPS虚拟主机上,通过云向用户提供存储和计算的服务. 现在硬件越来越便宜,一台非 ...

  5. FZu Problem 2236 第十四个目标 (线段树 + dp)

    题目链接: FZu  Problem 2236 第十四个目标 题目描述: 给出一个n个数的序列,问这个序列内严格递增序列有多少个?不要求连续 解题思路: 又遇到了用线段树来优化dp的题目,线段树节点里 ...

  6. Hdu 5446 Unknown Treasure (2015 ACM/ICPC Asia Regional Changchun Online Lucas定理 + 中国剩余定理)

    题目链接: Hdu 5446 Unknown Treasure 题目描述: 就是有n个苹果,要选出来m个,问有多少种选法?还有k个素数,p1,p2,p3,...pk,结果对lcm(p1,p2,p3.. ...

  7. 洛谷 P4317 花神的数论题 || bzoj3209

    https://www.lydsy.com/JudgeOnline/problem.php?id=3209 https://www.luogu.org/problemnew/show/P4317 设c ...

  8. 浅析String

    浅析String String的设计结构: 首先我们看一下 String的源码 public final class String     implements java.io.Serializabl ...

  9. Elipse 无法启动问题(转)

    来源: <http://www.cnblogs.com/coding-way/archive/2012/10/17/2727481.html> 当选择完workspace之后,eclips ...

  10. 用eclipse-inst-win64.exe安装eclipse出现Java for Windows Missing 的原因

    Java for Windows Missing 因为jdk的版本没有对,我这里是64位的机器上安了32位的jdk,所以一直报这个. 必须换上相对应版本的jdk,提示页面有链接,直接点击就可以下载. ...