Java并发编程学习前期知识下篇
Java并发编程学习前期知识下篇
通过上一篇《Java并发编程学习前期知识上篇》我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义。我们先来看看几个大厂真实的面试题:
从上面几个真实的面试问题来看,我们可以看到大厂的面试都会问到并发相关的问题。所以
Java并发,这个无论是面试还是在工作中,并发都是会遇到的。Java并发包JUC(java.util.concurrent)有了解过哪些?并发包实现最重要的是什么?其原理是什么知道吗?何为JMM的可见性?volatiile关键字是怎么实现变量可见性的?如果想要学好并发,弄懂理解透彻的话,凯哥觉得以下计算机的知识还是要了解了解。本次《Java并发编程-前期准备知识》凯哥准备用两篇来介绍,主要包括以下内容:简单介绍内存之间可见性是什么?volatile关键字在Java语言规范中是怎么定义的?知道JVM但是你知道JMM是什么吗?计算机中CPU是怎么处理数据的?通过CPU处理数据来深刻理解线程之间可见性。还有就是volatile是怎么保证可见性的呢?其实现的两条原理是什么?
CPU相关知识
先来看看凯哥电脑配置:
从上图,可以看到凯哥电脑
CPU处理是4核8线程,
缓存有三级。
其中一级数据缓存和指令缓存都是32K,
二级缓存256K,
三级缓存是6M.
电脑的内存是24G
为什么要说这些呢 ?
因为JVM运行程序的实体其实就是线程,而每个线程在创建的时候JVM都会给其创建一个工作内存(有些地方称之为:栈空间)。工作内存是每个线程自己的私有数据区域。Java内存模型中规定所有的变量都是存储在主内存中(也就是凯哥24G内内存中),主内存是共享内存区域,所有的线程都可以访问的(也就是说主内存中的数据,任意线程都可以访问)。但是线程对变量的操作,如读取,修改赋值操作是在从中内存中进行的。因此,一个线程要想操作一个变量,首先是要讲变量从主内存copy到自己的工作内存空间,然后再对自己工作空间中对变量操作,操作完成之后再将变量写回到主内存中去。线程是不能够直接操作主内存中的变量的。各个线程中的工作内存存储的其实就是主内存的一个变量副本拷贝。因此不同线程之间是无法访问到对方的工作内存的。线程间的通讯(值转递)必须通过主内存来完成的。
上面这么大一段话,可以简单对应凯哥电脑配置:
线程:其实就是凯哥CPU的4核8线程中的线程
主内存:就是凯哥本子上的24G物理内存条
线程工作内存空间:就是缓存(一二三级缓存区域)
线程工作原理,如下图:
说明:
主内存中变量int i= 0;
cpu1中的线程1获取到i变量的时候,会将i从主内存中copy一份到自己的工作区域,也就是cpu1 cache中,然后更新i的值为10;
cpu2中的线程2同样获取到i变量,从主内存中copy一份之后,在自己的工作区cpu2 cache中将i修改成了15;这种情况下就是多核多线程问题。
线程之间可见性深度理解
在这种情况下主内存中的i就是两个线程之间的共享变量了。那么怎么能确保cpu1的线程1修改i的值之后,通知cpu2中的线程2的工作区缓存无效呢?这个操作就是线程之间的可见性。
再举个现实生活中常用的例子:
比如,凯哥现在在和大家分享。今天我发布之后,你们大家在自己手机或者是PC网友上都能看到凯哥分享的知识点。这个时候有个网友A在看到凯哥分享的东西,感觉有点不好或者是举个其他的例子或者更容易理解。于是他把凯哥这个文章进行了修改。然后给凯哥留Y。告诉凯哥,凯哥看后,觉得很不错。等明天,凯哥发文章通知大家,如果用xxx的案例就跟容易让大家理解了。于是,你们大家知道,哦原来昨天的案例不是最新的了。放弃昨天的,看看今天最新的案例。
如果上面案例看着是多线程那么可以这么分析:
主内存:凯哥
共享变量:凯哥分享的知识点
多个线程:各位看凯哥分享的网友
其中网友A修改了知识点的内容(网友A修改的是自己手机上的(工作区的)知识点)后通知了凯哥,然后凯哥又通知了各位。各位知道原来自己手里的不是最新的了,然后放弃重新获取最新的。
这样来理解的话,就更容易理解线程的可见性
Volatitle是如何保证可见性的呢?
可以通过JIT编译器生成的汇编指令来查看对volatile进行写操作时候,CPU都做了哪些事情?
如下代码:
Volatile Singleton instance = new Singleton();
Instance是被volatitle修饰的。
在使用JIT编译器生成的汇编指令后,有一个重要的代码:
0x01a2de1d:xxxx:lock addl $0X0,(%esp);
我们可以看到,当一个共享变量被volatile修饰之后,在进行写操作的时候,会多出一些汇编代码Lock.在IA-32架构软件开发手册中,Lock前缀的指令当在多核处理器的时候会引发出两件事情:
1:将当前的处理器缓存行的数据写回的主内存中(也就是系统的物理缓存中);
2:同时这个写回内存的操作也会使其他CUP里缓存了内存地址的数据被置为无效。
Cpu处理数据方法:
为了提高处理数据,CPU不会直接从内存中获取数据操作的。
这里我们需要电脑处理数据的速度排序:磁盘(硬盘)<内存<高速缓存<CPU。我们可以看出CPU的操作速度比内存快很多。所以,如果CPU直接操作内存,不仅会影响处理速度还有可能让内存使用寿命变短。这个时候,高速缓存就解决这个问题的。
所以,CPU在处理数据的时候会像将内存中的数据到期到高级缓存中(就是一二三级缓存),然后再缓存中进行操作的。
在多核处理器的时候,为了保证各个处理器之间缓存变量是一致的,就需要实现缓存一致性协议。其操作就是:各个CPU通过嗅探在总线上传播的数据来实时检查自己缓存的值是不是已经过期了。如果发下自己缓存中的数据已经被修改了,则就会将当前的处理器中缓存数据状态设置为无效,当这个处理器需要对这个数据进行操作的似乎和,会重新从主内存中,把最新的数据读取到自己缓存中。
Volatile两条实现原理
1:汇编代码的lock前缀指令会引起处理器缓存写回到主内存中。
当有lock指令的缓存,在其声言期间,能搞保证处理器可以独占任何共享的内存。同时缓存一致性会阻止同时修改由两个以上处理器缓存的内存区域数据
2:当一个处理器的缓存写回到主内存中之后,会导致其他处理器的缓存无效
这个是处理器见的控制协议来维护内部缓存的
总结:
通过这两篇《Java并发编程前期准备知识》的了解,我们知道JMM,线程之间共享数据等知识,这样再接下来学习Java并发编程就会简单一些了。接下来欢迎进入Java并发编程学习中!
Java并发编程学习前期知识下篇的更多相关文章
- 学习笔记:java并发编程学习之初识Concurrent
一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...
- Java并发编程学习路线(转)
以前特地学过并发编程,但是没怎么学进去,不太喜欢.最近发现,作为一个资深工程师,却没有完整深入系统的学习过,而反是现在的BAT大并发是必须的,感觉甚是惭愧. 故找了一片学习文章,如下,准备集中一段时间 ...
- Java并发编程学习路线
一年前由于工作需要从微软技术栈入坑Java,并陆陆续续做了一个Java后台项目,目前在搞Scala+Java混合的后台开发,一直觉得并发编程是所有后台工程师的基本功,所以也学习了小一年Java的并发工 ...
- Java并发指南开篇:Java并发编程学习大纲
Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容. 这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类.当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中 ...
- Java并发编程学习:volatile关键字解析
转载:https://www.cnblogs.com/dolphin0520/p/3920373.html 写的非常棒,好东西要分享一下 Java并发编程:volatile关键字解析 volatile ...
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- [Todo] Java并发编程学习
有两个系列的博文,交替着可以看看: 1. Java并发编程与技术内幕 http://blog.csdn.net/Evankaka/article/details/51866242 2. [Java并发 ...
- java并发编程学习:用 Semaphore (信号量)控制并发资源
并发编程这方面以前关注得比较少,恶补一下,推荐一个好的网站:并发编程网 - ifeve.com,上面全是各种大牛原创或编译的并发编程文章. 今天先来学习Semaphore(信号量),字面上看,根本不知 ...
- Java并发编程学习笔记 深入理解volatile关键字的作用
引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...
随机推荐
- git 忽略规则
# 以'#'开始的行,被视为注释. # 忽略掉所有文件名是 foo.txt的文件. foo.txt # 忽略所有生成的 html文件, *.html # foo.html是手工维护的,所以例外. !f ...
- 吴裕雄--天生自然python学习笔记:Python3 多线程
多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条 ...
- TCP\IP协议簇-分层模型
OSI 模型 数据单元 层 功能 主机层 Data(数据) 7. 应用层 网络进程到应用程序. 6. 表示层 数据表示形式,加密和解密,把机器相关的数据转换成独立于机器的数据. 5. 会话层 主机 ...
- Errors running builder JavaScript Validator
问题: 解决方法: 方法一. 选择对应项目—-右键Properties—-Builders—-取消“JavaScript Validator”的勾就OK了 方法二. 找到“.project”文件,找到 ...
- 【C++基础】008常量和变量
简介:常量和变量. 常量和变量 1. 常量 具体把数据写出来 2,3,4: 1.2,1.3: "Hello World!","C++": cout <&l ...
- 通俗易懂DenseNet
目录 写在前面 Dense Block与Transition Layer DenseNet网络架构与性能 理解DenseNet Plain Net.ResNet与DenseNet 参考 博客:博客园 ...
- Leetcode 20题 有效的括号(Valid Parentheses) Java语言求解
题目描述: 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭合. 注意空 ...
- Nginx之负载节点状态监测
前言 nginx做负载均衡性能很好,但是负载中的节点有异常怎么处理呢? 当然是nginx发现某一个节点为异常节点后自动将请求转移至其他节点直至转移到一个正常节点. 为了实现这一步有如下两个解决方案可供 ...
- JavaScript 执行环境以及作用域链
执行环境(execution context,为简单起见,有时也称为"环境")是 JavaScript 中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们 ...
- Leetcode1353_最多可以参加的会议数目
题目地址 给定n个会议时间区间,会议不用全程参加,问最多能参加的数目. 时间区间按左端点排序,扫一遍,每一天把当天开始的区间结束时间加入,同时把这一天之前结束的区间删掉,然后贪心从最小堆取出结束时间的 ...