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并发编程学习中!
相关推荐
"13-Java并发编程学习宝典.zip" 包含了一系列关于Java并发编程的学习资源,旨在帮助开发者掌握多线程编程的核心技术和最佳实践。以下是这些资源所涵盖的关键知识点: 1. **多线程基础** - "03 多线程开发如此简单—...
在Java并发编程中,数据的封装与访问控制、线程安全性的考量、同步...以上知识点是从提供的文件内容中提取出的,旨在帮助理解Java并发编程的基础概念和技术实践。掌握这些概念对于开发高效且可靠的并发程序至关重要。
Java并发编程与高并发解决方案是开发高性能应用的关键技术...掌握以上基础知识是Java并发编程和解决高并发问题的关键。在实际开发中,还需要根据具体业务场景灵活运用,并结合性能测试进行调优,以达到最佳的并发性能。
总的来说,《Java并发编程之美》是一本系统而全面的并发编程教程,无论你是想提升面试技巧,还是解决高并发场景下的挑战,都能在书中找到答案。通过阅读和实践,你将能够在Java并发编程的世界里游刃有余。
### Java并发编程基础知识 1. **线程**: Java中的线程是程序执行的基本单位,每个线程都有自己的堆栈空间和执行上下文。 - 创建线程的方法有两种:继承`Thread`类或实现`Runnable`接口。 - `Thread`类提供了多种...
本篇主要探讨了Java并发编程中的基本概念、优缺点、线程与进程的区别以及线程的状态转换。 首先,我们来了解一下并发编程的优缺点。并发编程的优点在于能够充分利用多核CPU的计算能力,提高系统性能,特别适合处理...
最后推荐大家阅读《Java并发编程实战》一书,这本书提供了大量实用的案例和深入浅出的讲解,非常适合希望深入学习Java并发编程的读者。虽然提供的链接似乎并不是该书籍的直接下载地址,但可以通过搜索引擎或其他途径...
在Java并发编程中,volatile关键字扮演着至关重要的角色,它提供了线程间的可见性和部分内存屏障,以确保共享变量在多线程环境下的正确性。然而,在实际应用中,开发者可能会遇到一些意料之外的问题,这通常是因为对...
《Java多线程编程实战指南-...通过《Java多线程编程实战指南-核心篇》,你可以深入了解Java并发编程的各个方面,提升在高并发场景下的编程能力。书中的案例和练习将帮助你更好地掌握理论知识,并将其应用于实际项目中。
Java并发编程之美_部分31 本篇章节主要讲解了 Java 中的并发编程相关知识,包括乐观锁、公平锁、非公平锁、独占锁和共享锁等概念。 首先,介绍了乐观锁的概念,乐观锁是一种无锁机制,通过在表中添加版本号或业务...
Java并发编程是Java开发中不可或缺的一部分,它涉及到多线程、多进程以及系统资源的高效利用。本篇文章将深入探讨并发编程的基本概念、学习路径、重要性和挑战,以及线程的状态转换。 首先,我们需要理解并发与并行...
总的来说,这本书全面覆盖了高并发编程中的关键知识点,包括多线程原理、线程池实现、并发控制、分布式系统架构以及面试技巧,适合有志于提升并发编程能力的后端开发者阅读,尤其是对分布式锁和Java并发编程感兴趣的...
核心方法与框架》、《Java并发编程:设计原则与模式(第二版)》、《Java并发编程实战(中文版)》、《Java多线程编程核心技术_完整版》以及《Java多线程编程实战指南 设计模式篇》,都是深入理解Java并发编程的宝贵...
本篇将基于书中的内容,结合并发编程的核心概念,为你详解Java并发编程的相关知识点。 首先,我们要了解什么是并发。并发是指多个任务在一段时间内交替执行,而不是一个接一个地顺序执行。在Java中,通过线程来实现...
本篇文章将深入探讨`synchronized`的使用及其在Java并发编程中的作用。 首先,`synchronized`关键字的主要功能是实现线程同步,确保同一时间只有一个线程可以执行特定的代码段。这在处理共享数据时尤为重要,因为它...
这篇博文链接(https://weigang-gao.iteye.com/blog/2207335)可能深入讨论了Java并发编程的实践和技巧。 在Java中,我们有多种方式来创建和管理线程,包括`Thread`类的实例化、实现`Runnable`接口、使用`...
理解`Executors`类的用法仅仅是Java并发编程的一部分,还需要掌握`Future`、`Callable`接口,以及`Runnable`和`Thread`的区别。此外,`ExecutorService`接口提供的`submit()`、`execute()`等方法也是并发编程中经常...
《JAVA并发编程与高并发解决方案-并发编程四之J.U.C之AQS》是一篇详细介绍Java实用并发工具包(Java Util Concurrency,简称J.U.C.)中重要组成部分——AbstractQueuedSynchronizer(简称AQS)的文章。AQS是Java并发...
本篇将通过实战范例,逐步解析 Java 并发编程的关键概念和技术,帮助开发者从基础到进阶,全面理解并发编程的核心。 一、并发编程基础 1. **线程**:Java 中的线程是并发执行的基本单元。`Thread` 类提供了创建和...