java内存模型说的是多线程,网上可能会有写误导,并不是什么堆、栈、方法区,很多人都会搞混。说白了就是多线程中主线程和本地线程之间的一个数据可见性问题。

jmm:java内存模型;jvm:java内存结构

先看看多线程特性:

1、原子性:保证数据一致性和安全性

2、可见性:保证主线程中的共享变量进行修改后,本地线程能第一时间知道,这就是可见性,下面会配图和代码进行说明

3、有序性:jvm的一个重排序,提高线程的运行效率的

下面来看看java内存模型,代码很简单

package com.springboot;

/**
* @Title: Java内存模型
* @Description:
* @author: sunxuesong@hztianque.com
* @date: Created in 9:18 2019/8/4
* @Modifired by:
*/
public class Thread001 extends Thread { private boolean flag = true; /**
* 子线程
*/
@Override
public void run() {
System.out.println("线程开始.."); while (flag) { }
System.out.println("线程结束..");
} public void setFlag(boolean flag) {
this.flag = flag;
} /**
* 主线程
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Thread001 thread001 = new Thread001(); thread001.start();
Thread.sleep(3000);
thread001.setFlag(false);
System.out.println("flag已经改为false");
Thread.sleep(1000);
System.out.println("flag:" + thread001.flag);
}
}

结果:

可以看到线程进入了死循环,主线程明明已经修改了值为false但是子线程就是看不见,这就是可见性的问题。

怎么修改呢?其实很简单只需要在主线程中的flag变量前面加一个关键字,下面在看看结果:

加了关键字之后三秒后直接跳出死循环,这个关键字volatile可以保证当主线程中的值刷新了之后会立马通知到子线程。

但是volatile只能保证数据的可见性,不能保证原子性。延伸一点知识volatile和synchronize区别:

volatile比synchronize性能上要好很多,但是不能保证数据原子性。

synchronize性能上比volatile差很多,因为他在并发情况下只能有一个线程去执行,但是可以保证数据的原子性。

下面说一下Java的内存结构:jvm

jvm主要结构有方法区、堆、栈

方法区:加了static关键字的都是放在方法区中,它是存放在永久区中是不会被垃圾回收机制进行回收的,所以static关键字要慎用(又称为永久区),当class文件被加载就会被初始化

堆:通过关键字new出来的对象都是放在堆内存中,垃圾回收也是针对堆进行

栈和本地方法区:局部变量和类的方法,代码运行完毕自动释放内存,每个线程都是私有的,不会共享,也不会产生线程安全问题

下面用代码对方法区就行说明:很有趣的代码

public class Test001 {

    private int count = 0;

    /**
* 毫无疑问结果是2
* @param args
*/
public static void main(String[] args) {
Test001 test001 = new Test001();
++ test001.count;
++ test001.count;
System.out.println(test001.count);
}
}

再来看一个代码:


  private static int count = 0;
  /**
* 结果也是2
* 因为static修饰的变量它存放在方法区中,是被所有线程所共享的,或者说是jvm中全局的变量
   * 不要定义太多的常量,有可能会出现内存溢出的情况,这也是jvm内存调优的一种方式,但是主要调优策略是在堆中,不是在方法区
* private static Test001 test003 = new Test001();这也是存放在方法区中,不要误解,凡是加了static都是存放在方法区中
* @param args
*/
public static void main(String[] args) {
Test001 test001 = new Test001();
Test001 test002 = new Test001();
++ test001.count;
++ test002.count;
System.out.println(test001.count);
}

jvm的内存结构就是这样子的了,切记内存模型和内存结构不要混淆,下节说一下jvm的垃圾回收机制

java内存模型和内存结构的更多相关文章

  1. java并发学习--第十章 java内存模型的内存语义

    一.锁的内存语义 所为的java内存模型的内存语义指的就是在JVM中的实现原则. 锁的内存语义:锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息. 我们把上面这句话再整理下: ...

  2. JVM并发机制的探讨——内存模型、内存可见性和指令重排序

    并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”. 从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富加多了机器,需要协调多台机器或者多个CP ...

  3. jvm内存模型-和内存分配以及jdk、jre、jvm是什么关系(阿里,美团,京东)

    参考:JVM的垃圾回收机制 总结(垃圾收集.回收算法.垃圾回收器) 1.什么是jvm?(1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的.(2) ...

  4. Java内存模型与内存结构

    Java内存模型 一.简介 Java内存模型(JMM)主要是为了规定线程和内存之间的一些关系:根据JMM的设计,系统存在一个主内存(Main Memory)和工作内存(Work Memory),Jav ...

  5. Java 内存模型与内存结构

    Java内存模型 一.简介 Java内存模型(JMM)主要是为了规定线程和内存之间的一些关系:根据JMM的设计,系统存在一个主内存(Main Memory)和工作内存(Work Memory),Jav ...

  6. JAVA高级篇(二、JVM内存模型、内存管理之第一篇)

    JVM内存结构如 Java堆(Heap),是Java虚拟机所管理的内存中最大的一块.Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建.此内存区域的唯一目的就是存放对象实例,几乎所有的对象实 ...

  7. 【深入Java虚拟机】之一:Java内存模型与内存溢出

    [深入Java虚拟机]之:Java内存区域与内存溢出 高速缓存模型如下: ----------------------------------------------------分割线-------- ...

  8. java内存模型,内存区域

    Java虚拟机内存区域总结:Java虚拟机相当于一个抽象的计算机操作系统, 其管理的内从区域大体上可以分为栈和堆,就像c或c++中对内存的分类一样, 但这样的分类对于Java虚拟机来说太过粗浅, 实际 ...

  9. jvm内存模型和内存分配

    1.什么是jvm? (1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的. (2)jvm包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和 ...

随机推荐

  1. php修改网站默认编码

    php修改网站默认编码网站如果header 不指定utf8默认 不是utf8 所以输入中文显示会乱码 一般都是apache不是不是utf8 打开 apache 配置文件 httpd.conf 加个 A ...

  2. python 读取文件路径

    python 读取文件路径 一定要用绝对路径不能用相对路径 不然读取不出来 <pre>img = cv.imread("F:\\wef\\wef\\jiaoben\\e\\1.j ...

  3. 一次shardingjdbc踩坑引起的胡思乱想

    项目里面的一个分表用到了sharding-jdbc 当时纠结过是用mycat还是用sharding-jdbc的, 但是最终还是用了sharding-jdbc, 原因如下: 1. mycat比较重, 相 ...

  4. js常用的array方法

      1. splice() splice()方法向/从数组中添加/删除项目,然后返回被删除的项目.(注释:该方法会改变原始数组.) arrayObject.splice(index,howmany,i ...

  5. [LC]235题 二叉搜索树的最近公共祖先 (树)(递归)

    ①题目 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖先 ...

  6. 这份最新Python面试精选问题你会几道?

    相信很多小伙伴学python以后都想进大厂,但是进大厂前你得了解些大厂面试题,可以在面试前复习下,以下是精选的5道python面试题: 第一. Python 的特点和优点是什么? Python 可以作 ...

  7. nyoj 22-素数求和问题(打表)

    22-素数求和问题 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:41 submit:52 题目描述: 现在给你N个数(0<N<1000 ...

  8. nyoj 96-n-1位数 (strlen, atoi, ceil)

    96-n-1位数 内存限制:64MB 时间限制:3000ms 特判: No 通过数:30 提交数:47 难度:1 题目描述: 已知w是一个大于10但不大于1000000的无符号整数,若w是n(n≥2) ...

  9. CCF-画字符-详细的注释

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.i ...

  10. shell命令管道未读完阻塞了子进程,与等待其结束的父进程死"锁"。

    在exec执行一个子进程,我们希望使用管道取得子进程在重定向后的标准输出上的结果,同时等待子进程的结束.那么是等待子进程结束后才取管道数据,还是边取数据边等待子进程结束呢? 这里有一个调试的例子.u0 ...