Java 复习 —— JMM基础

基本内容

1、共享变量在线程间的可见性

2、synchronized实现可见性

3、volatile 实现可见性

1)指令重排序

2)as-if-serial

3)volatile 使用注意事项

4、volatile和synchronized的比较

1、可见性

一个线程对共享变量值的修改,能够及时地被其他线程看到。

共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。

Java内存模型(JMM):描述了Java程序中各种变量(共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。

2、JMM 基本规则

1)所有的变量都存储在在主内存中。

2)每个线程都有自己独立的工作内存,里面保存该线程使用到的变量副本(主内存中该变量的一份拷贝)。

3)线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写

4)不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。

3、共享变量实现可见性的原理

1)首先在自己线程Thread1里修改共享变量x=1

2)然后更新主内存的x=1

3)其次其他线程Thread2从主内存中读取x=1,更新自己线程的值,

这样连续性的操作,可以保证任何一个线程的独立内存中的共享变量都是最新的值!

4、Java层面实现可见性的方式

1)synchronized

2)volatile

3)concurrent 包

5、synchronized

1)线程解锁前,必须把共享变量的最新值刷新到主内存中

2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值。(注意:加锁与解锁需要同一把锁)

6、synchronized 修饰时,JVM操作的步骤

1)首先获得互斥锁

2)清空工作内存

3)从主内存拷贝变量的最新副本到工作内存

4)执行代码

5)将更改后的共享变量值刷新到主内存

6)释放互斥锁

7、重排序

代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化!

1)编译器优化

2)指令优化

3)内存系统优化

最后的结果:有可能导致代码的执行的顺序与编写顺序不一致,但是可以提高CPU性能

8、as-if-serial

无论如何重排序,程序的运行结果都是保持一致的!

单线程中是不能会因为重排序带来内存可见性的问题。

多线程则会由于重排序带来共享变量不一致的问题。

9、导致共享变量在线程间不可见的原因

1)线程交叉执行。(原子性来保证)

2)重排序结合线程交叉执行。(原子性来保证)

3)共享变量未及时更新。(内存可见性来保证)

10、synchronized 修饰变量、修饰方法或代码块

1)拥有原子性

2)拥有内存可见性

3)重量级

所以他能够实现线程间执行操作的安全性!

11、volatile 修饰变量

1)不保证原子性

2)拥有可见性

3)轻量级

12、关于 i++

1)首先读取,从主内存中读取i的值更新到当前工作内存中

2)其次改变,对i进行加1

3)最后更新,从当前工作内存中的值刷新到主内存中去

所以,这不是一个原子操作,在这个操作过程中势必会导致线程间交互而导致值的混乱!解决方式就是保证 i++ 具有原子性

1)使用synchronized

2)使用Lock对象,concurrent 包中

Lock lock = new RentrantLock();

try{

lock.lock();

i++

}finally{

lock.unlock();

}

13、volatile 使用场合

1)对变量的写入操作不依赖其当前值,比如Boolean值,但是 i++ 或 i=i+5

2)该变量没有包含在其他变量的不变式中,比如: low < high (这里我也不是很清楚)

注意:共享变量都必须是private

final 也实现了内存可见性,因为他的值是不可修改的!

14、结论

对一个共享变量不仅仅要关心他的写,还关心他的读,二者都要加锁;

volatile是轻量级的,能使用,尽量使用!

时间: 2024-11-09 14:54:02

Java 复习 —— JMM基础的相关文章

Java 复习 —— 语言基础

基础概念 1.标识符:由字母.下划线.数字.美元符号组成,但是不能以数字开头. 2.关键字:50个关键字,goto虽然不存在,但是依然是关键字 3.变量:其命名规范不一定是按照标识符来,其可以是中文等 数据类型 1.Java共8种原生数据类型(另外一种就是引用类型),可分为四组 1)逻辑类型:boolean 2)字符类型:char 3)浮点类型:float.double 4)整数类型:byte short int long 2.数据类型精度排序: byte(1).short(2).char(2)

Java 复习 —— 多线程基础

1.基本概念 1)进程:运行当中的程序,程序是静止的概念,进程的是动态的概念,进程与进程之间互不运影响 2)线程:指程序中单独顺序的流控制,线程依附于进程中,他是最小的执行单位!一个任务一个线程. 3)多线程:指的是单个程序中可以同时运行多个不同的线程,执行不同的任务.(本身就要把线程理解为为不同的任务而服务的) 4)二者关系:一个进程当中可以有一个或多个线程,但是至少有一个线程. 2.作用与关系 1)多线程的目的:最大限度利用CPU资源 2)主线程:Java程序默认启动一个线程就是main线程

Java 笔记之基础复习

1.& 与 &&的区别 两个都有逻辑与的功能.但是所不同的是,当&两边的表达式不是boolean类型的时候,&具有位与的功能:&&是短路与,当判断到前一个表达式为false的时候,将不会再去计算后面的表达式. 如: int i = 0; System.out.println((1==0)&(0==(i++))); System.out.println(i); 输出是: false 1 但是, int i = 0; System.out.pri

Java复习第二天---JavaSE基础

[1]以下关于 JVM 的叙述,哪些项正确? A.JVM 运行于操作系统之上,它依赖于操作系统 B.JVM 运行于操作系统之上,它与操作系统无关 C.JVM 支持 Java 程序运行,它能够直接运行 Java 字节码文件 D.JVM 支持 Java 程序运行,它能够直接运行 Java 源代码文件 扩展名为.java的是源代码文件(文本文件):开发时编写代码的文件 扩展名为.class的是字节码文件(二进制):系统运行时执行的文件 [2]下列选项中正确的表达式是: A.byte b = 128; 

2.2JAVA基础复习——JAVA语言的基础组成运算符和语句

JAVA语言的基础组成有: 1.关键字:被赋予特殊含义的单词. 2.标识符:用来标识的符号. 3.注释:用来注释说明程序的文字. 4.常量和变量:内存存储区域的表示. 5.运算符:程序中用来运算的符号. 6.语句:程序中常用的一些语句. 7.函数:也叫做方法,用来做一些特定的动作. 8.数组:用来存储多个数据的集合. JAVA中的运算符 1.算术运算符:用来进行一些数据算法的符号 算术运算符分为单目运算符.双目运算符.三目运算符. 单目运算符有:+(取正)-(取负)++(自增)--(自减)代码如

2.1JAVA基础复习——JAVA语言的基础组成注释和常量变量

/** 这是 JAVA中独有的多行注释 */ JAVA语言的基础组成有: 1.关键字:被赋予特殊含义的单词. 2.标识符:用来标识的符号. 3.注释:用来注释说明程序的文字. 4.常量和变量:内存存储区域的表示. 5.运算符:程序中用来运算的符号. 6.语句:程序中常用的一些语句. 7.函数:也叫做方法,用来做一些特定的动作. 8.数组:用来存储多个数据的集合. JAVA中的注释: 注释还可以用来缩小程序错误的范围,方便查找错误. // :表示单行注释. //这是一个单行注释 /**/:表示多行

1.JAVA基础复习——计算机基础与环境变量配置

软件开发的了解 软件开发: 软件:一系列按照特定组织的计算机数据和指令的集合. 开发:制作软件. 程序:一系列有序指令的集合. 人机交互 人机交互的方式有两种:图形化界面和命令行方式. 图形化界面:简单直观易于操作. 命令行方式:需要一个控制台需要了解一些特定的指令,较为麻烦. 计算机语言 语言:是人与人之间沟通的一种方式. 计算机语言:是人与计算机交流的方式. Java语言概述 由Sun公司1995年推出的一门语言. 特点:简单易学,完全面向对象,跨平台. Java三大版本 J2SE:标准版,

Java复习第一天---Javascript的基本知识点

1.HelloWord: 2.基础语法: 3.嵌入HTML 借助window.onload事件在整个窗体载入完毕之后运行程序代码 4.事件驱动: 5.DOM操作 5.1 查找元素节点 5.1.1 依据id值 方法:document.getElementById(id值) 获取到的是一个元素节点 var bj = document.getElementById("bj"); alert(getText(bj)); 5.1.2 依据标签名 方法:document.getElementsBy

java 复习001

java 复习001 比较随意的记录下我的java复习笔记 ArrayList 内存扩展方法 分配一片更大的内存空间,复制原有的数据到新的内存中,让引用指向新的内存地址 ArrayList在内存不够时默认是扩展为1.5倍 + 1个 ArrayList,LinkedList,Vector 区别 Vector内存扩展和ArrayList一样,不过Vector是默认扩展为2倍 Vector支持线程的同步,因此牺牲了访问性能 ArrayList,Vector都是使用数组实现,插入删除效率低 Linked