说说你对JMM内存模型的理解?为什么需要JMM?多线程有什么用?

说说你对 JMM 内存模型的理解?为什么需要 JMM?说说 CyclicBarrier CountDownLatch 的区别?
随着 CPU 和内存的发展速度差异的问题,导致 CPU 的速度远快于内存,所以现在的 CPU 加入了高速
缓存,高速缓存一般可以分为 L1 L2 L3 三级缓存。基于上面的例子我们知道了这导致了缓存一致
性的问题,所以加入了缓存一致性协议,同时导致了内存可见性的问题,而编译器和 CPU 的重排序
导致了原子性和有序性的问题, JMM 内存模型正是对多线程操作下的一系列规范约束,因为不可能
让陈雇员的代码去兼容所有的 CPU ,通过 JMM 我们才屏蔽了不同硬件和操作系统内存的访问差异,
这样保证了 Java 程序在不同的平台下达到一致的内存访问效果,同时也是保证在高效并发的时候程
序能够正确执行。
原子性 Java 内存模型通过 read load assign use store write 来保证原子性操作,此外还有
lock unlock ,直接对应着 synchronized 关键字的 monitorenter monitorexit 字节码指令。 可见性 :可见性的问题在上面的回答已经说过, Java 保证可见性可以认为通过 volatile
synchronized final 来实现。
有序性 :由于处理器和编译器的重排序导致的有序性问题, Java 通过 volatile synchronized 来保
证。
happen-before 规则
虽然指令重排提高了并发的性能,但是 Java 虚拟机会对指令重排做出一些规则限制,并不能让所有
的指令都随意的改变执行位置,主要有以下几点:
1. 单线程每个操作, happen-before 于该线程中任意后续操作
2. volatile happen-before 与后续对这个变量的读
3. synchronized 解锁 happen-before 后续对这个锁的加锁
4. final 变量的写 happen-before final 域对象的读, happen-before 后续对 final 变量的读
5. 传递性规则, A 先于 B B 先于 C ,那么 A 一定先于 C 发生
说了半天,到底工作内存和主内存是什么?
主内存可以认为就是物理内存, Java 内存模型中实际就是虚拟机内存的一部分。而工作内存就是
CPU 缓存,他有可能是寄存器也有可能是 L1\L2\L3 缓存,都是有可能的。
多线程有什么用?
一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这
个回答更扯淡。所谓 " 知其然知其所以然 " " 会用 " 只是 " 知其然 " " 为什么用 " 才是 " 知其所以然 " ,只
有达到 " 知其然知其所以然 " 的程度才可以说是把一个知识点运用自如。 OK ,下面说说我对这个问题
的看法:
1 )发挥多核 CPU 的优势
随着工业的进步,现在的笔记本、台式机乃至商用的应用服务器至少也都是双核的, 4 核、 8 核甚至
16 核的也都不少见,如果是单线程的程序,那么在双核 CPU 上就浪费了 50% ,在 4 CPU 上就浪费
75% 单核 CPU 上所谓的 " 多线程 " 那是假的多线程,同一时间处理器只会处理一段逻辑,只不过
线程之间切换得比较快,看着像多个线程 " 同时 " 运行罢了 。多核 CPU 上的多线程才是真正的多线
程,它能让你的多段逻辑同时工作,多线程,可以真正发挥出多核 CPU 的优势来,达到充分利用
CPU 的目的。
2 )防止阻塞
从程序运行效率的角度来看,单核 CPU 不但不会发挥出多线程的优势,反而会因为在单核 CPU 上运
行多线程导致线程上下文的切换,而降低程序整体的效率。但是单核 CPU 我们还是要应用多线程,
就是为了防止阻塞。试想,如果单核 CPU 使用单线程,那么只要这个线程阻塞了,比方说远程读取
某个数据吧,对端迟迟未返回又没有设置超时时间,那么你的整个程序在数据返回回来之前就停止 运行了。多线程可以防止这个问题,多条线程同时运行,哪怕一条线程的代码执行读取数据阻塞,
也不会影响其它任务的执行。
3 )便于建模
这是另外一个没有这么明显的优点了。假设有一个大的任务 A ,单线程编程,那么就要考虑很多,
建立整个程序模型比较麻烦。但是如果把这个大的任务 A 分解成几个小任务,任务 B 、任务 C 、任务
D ,分别建立程序模型,并通过多线程分别运行这几个任务,那就简单很多了。
说说 CyclicBarrier CountDownLatch 的区别?
两个看上去有点像的类,都在 java.util.concurrent 下,都可以用来表示代码运行到某个点上,二者
的区别在于:
1 CyclicBarrier 的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了
这个点,所有线程才重新运行; CountDownLatch 则不是,某线程运行到某个点上之后,只是给某
个数值 -1 而已,该线程继续运行
2 CyclicBarrier 只能唤起一个任务, CountDownLatch 可以唤起多个任务
3 CyclicBarrier 可重用, CountDownLatch 不可重用,计数值为 0 CountDownLatch 就不可再
用了
  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值