线程的内存模型

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. python 字符串操作二 内建函数

    一.查看字符串的内建函数 >>> dir(str) ['__add__', '__class__', '__contains__', '__delattr__', '__dir__' ...

  2. bzoj 2648: SJY摆棋子【KD-tree】

    其实理论上cdq更优 核心是依次取x值.y值的mid作为当前节点,向两边递归建立二叉树,树上维护size:子树大小:mx[0/1]:子树内最大x/y:mn[0/1]:子树内最小x/y:d[0/1]:这 ...

  3. P5110 块速递推

    传送门 为啥我就没看出来有循环节呢-- 打表可得,这个数列是有循环节的,循环节为\(10^9+6\),然后分块预处理,即取\(k=sqrt(10^9+6)\),然后分别预处理出转移矩阵\(A\)的\( ...

  4. Luogu P1552 [APIO2012]派遣【左偏树】By cellur925

    题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...

  5. 知乎模拟登录 requests session

    Python 3.5 # -*- coding: utf-8 -*- """ Created on Wed May 3 16:26:55 2017 @author: x- ...

  6. hdu1232 畅通工程 基础并查集

    #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> ...

  7. SUSAN角点检测

    close all; clear all; I=imread('corner2.gif'); [posX,posY]=susan(I,); figure; imshow(I);hold on; plo ...

  8. LookupError: unknown encoding: idna 的处理方法

    写了一个脚本,想把它打包成exe文件,在python编译器中运行正常,但是打包成.exe文件运行报错 LookupError: unknown encoding: idna 找遍资料终于找到了解决方法 ...

  9. C#实现较为实用的SQLhelper

    第一次写博客,想不到写什么好b( ̄▽ ̄)d ,考虑的半天决定从sqlhelper开始,sqlhelper对程序员来说就像helloworld一样,很简单却又很重要,helloworld代表着程序员萌新 ...

  10. 获得select被选中option的value和text

    一:JavaScript原生的方法 1:得到select对象: var myselect=document.getElementById(“test”); 2:得到选中项的索引:var index=m ...