Java(1):多线程内存模型和状态切换

线程的内存模型

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()方法实现线程操作,唯一的区别在于前者限制了当前类不能再有其他业务上的继承父类。

 1 public class App1 extends Thread {
 2     @Override
 3     public void run() {
 4         super.run();
 5         System.out.println(Thread.currentThread().getName() + " : start");
 6     }
 7
 8     public static void main(String[] args) {
 9         App1 thread = new App1();
10         thread.setName("App1 Thread");
11         thread.start();
12         System.out.println(Thread.currentThread().getName() + " : start");
13     }
14 }
15
16 public class App1 implements Runnable {
17     @Override
18     public void run() {
19         System.out.println(Thread.currentThread().getName() + " : start");
20     }
21
22     public static void main(String[] args) {
23         Thread app1Thread = new Thread(new App1());
24         app1Thread.setName("App1 Thread");
25         app1Thread.start();
26         System.out.println(Thread.currentThread().getName() + " : start");
27     }
28 }

线程的启动方式:
#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)。

原文地址:https://www.cnblogs.com/leo-chen-2014/p/9271447.html

时间: 2024-11-06 03:31:32

Java(1):多线程内存模型和状态切换的相关文章

Java虚拟机:内存模型详解

版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实例的时候,虚拟机要为对象分配内存,Java虚拟机又是如何配分内存的呢?这些都涉及到Java虚拟机的内存划分机制,今天我们就来探究一下Java虚拟机的内存模型. Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间,有的区域随

进程与线程(二) java进程的内存模型

从我出生那天起,我就知道我有个兄弟,他桀骜不驯,但实力强悍 ,人家都叫它C+++            ----java 上回说到了,C进程的内存分配,那么一个java运行过程也是一个进程,java内存是如何分配的呢? http://blog.csdn.net/shimiso/article/details/8595564 详情请看:http://blog.csdn.net/a859522265/article/details/7282817 1.学习java,学过java多线程,没有学过多进程

java虚拟机之内存模型

1. 概述 对于从事 C.C++ 程序开发的人员来说,在内存管理领域,他们既是拥有最高权力的「皇帝」又是从事基础工作的「劳动人民」 --- 既拥有每个对象的「所有权」,又担负着每一个对象生命开始到终结的维护责任. 但是对于 java 程序员来说,在虚拟机自动内存管理机制的帮助下,不需要再为每一个 new 操作写配对的 delete/free 代码,不容易出现在内存泄漏和内存溢出问题,由虚拟机管理内存这一切看起来都很美好.不过,也正是因为 java 程序员把内存控制的权利交给了 java 虚拟机,

关于JAVA中的static方法、并发问题以及JAVA运行时内存模型

一.前言 最近在工作上用到了一个静态方法,跟同事交流的时候,被一个问题给问倒了,只怪基础不扎实... 问题大致是这样的,"在多线程环境下,静态方法中的局部变量会不会被其它线程给污染掉?": 我当时的想法:方法中的局部变量在运行的时候,是存在JAVA栈中的,方法运行结束,局部变量也就都弹光了,理论上单线程的话是不会有问题的,我之所以不知道,是因为不清楚在JAVA内存模型中,一个线程对应一个栈,还是多个线程共享一个栈... 其实如果知道每个线程都有一个自己的JAVA栈的话,问题也就很清楚了

Java的多线程编程模型5--从AtomicInteger开始

Java的多线程编程模型5--从AtomicInteger开始 2011-06-23 20:50 11393人阅读 评论(9) 收藏 举报 java多线程编程jniinteger测试 AtomicInteger,一个提供原子操作的Integer的类.在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字.而AtomicInteger则通过一种线程安全的加减操作接口. 来看AtomicInteger提供的接口. //获取当前的值 publ

Java的虚拟机内存模型

JVM是JavaVirtualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java语言的一个非常重要的特点就是与平台的无关性.而使用Java虚拟机是实现这一特点的关键.一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码.而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译.Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程

Java虚拟机的内存模型

一.问题起源 这篇文章的起源其实是博主想要学习Java并发,计算机并发的痛点在于一方面cpu越来越多核化,另外 一个方面就是cpu和存储以及通信子系统的速度差距太大,大概来说,cpu速度是ns级,内存100ns,硬盘ms,内存比cpu慢100倍, 硬盘比cpu慢100万倍,cpu如果-等这些速度慢的多的小伙伴,势必造成计算资源的浪费.物理机为了解决cpu与内存的速度差, 在两者之间加入了缓存,有缓存就会引入新问题,即缓存一致性问题. 图1(图片来自参考文献[1]) 为了解决缓存一致性问题,各个c

深入理解Java虚拟机笔记---内存模型

主内存与工作内存 Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量值这样的底层细节.此处的变量(Variable)与Java编译中所说的变量略有区别,它包括了实例字段,静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为后者是线程私有的,不会被共享,自然就不存在竞争的问题.了为获得比较好的执行效率,Java内存模型并没有限制执行引擎使用处理器的特定寄存器或缓存来和主内存进行交互,也没有限制即时编译器调整代码执行顺序这类权限. J

Java并发之内存模型-JMM

1.总括 并发编程模型主要处理两个问题:线程之间如何通信及线程之间如何同步.通信:线程之间以何种机制来交换信息:同步:程序用来控制不同线程之间操作发生相对顺序的机制. 发生线程安全性的时机: 变量存储在内存中,变量的计算是在CUP中.如果线程A要对变量a进行计算,需要经过三步:1)把变量a从内存中读取到CPU中,2)对变量a进行计算,3)把变量a写入到内存中.当线程A执行到第二步时,线程B也要对变量a进行计算,这时B从内存中读取到的值就是线程A写入到内存之前的值,脏数据就此产生了. 在命令式编程