首页 > 编程语言 >极客时间 Java并发编程实战 笔记

极客时间 Java并发编程实战 笔记

时间:2023-02-01 00:56:24浏览次数:63  
标签:初始化 极客 Java 对象 编程 加锁 线程 volatile 资源

思考、再思考、总结、再总结

01 可见性、原子性和有序性

举几个例子先。

  1. 缓存可能导致可见性问题,因为多核CPU上的多个核可能都持有同一数据的不同缓存。两个线程并行地对一个字段进行累加,结果介于一倍与两倍之间。关键字volatile就是为了这样的需求,它提示底层去掉缓存这样的优化,从而使得任何写入,对于之后的读取都是可见的。
  2. 线程切换带来原子性问题,因为切换去切换来的中间可能会修改本线程也关注的数据,好比git维护着的多个版本之间merge的时候会因为改动了同一个数据而报冲突,以前或许是改同一个文件就冲突,现在更聪明了,该同一行才会冲突。
  3. 再举一个原子性(也是有序性)的问题 —— 一行命令可能对应于多条底层命令,比如,原本C语言的内存申请和初始化是分开的,但面向对象模型引入后,new一个对象不但申请了对象需要的内存空间大小,还执行了对象的初始化,不了解这个过程可能误觉这是原子的,但其实,可能在这中间有其他线程访问了这个对象,发现它是非空的,并访问了这个未初始化的对象。而这个对象可以被其他线程访问,是由于可能存在指令重排,导致对象在初始化之前被返回;而另一个线程在临界区之外判空并返回该未初始化对象,这就导致本来想提高效率的双重判空检查反而使得临界区失效了,自己这边在临界区内还在准备要准备,另一个线程已经拿到了这个对象。

02 内存模型

  1. 单线程内的命令是顺序性的和传递性的,如果再引入volatile,那么会使得volatile变量赋值紧挨着的之前的非volatile变量赋值也具有volatile的属性。
  2. 类似地,线程的start能看到其调用点之前到结果,join的结果则为调用点之后可见。

03 加锁与临界区

  1. 加锁是一个很好的解决并发冲突的办法。但是,加锁的范围大了,影响效率;小了,临界区就失效了,就像双重判空检查那样的。
  2. 通常,用一把锁来锁相关联的多个资源(在面向对象编程语言中,资源就是对象,尤其是作为字段的被管理的对象);但如果多个资源并非一定要关联在一起,那么,为了提高效率,可以给每一个资源加一个各自的锁。就像数据库的表级锁和行级锁。但是,在采取后者的情况下,又得对偶尔的关联情况做预防,好比,一个系统为每一个用户建立了各自的账本,如果没有转账行为,或者没有并发的转账行为,那么是相安无事的;否则,情况就是可能死锁。

04 死锁

死锁的条件:

  1. 占用且等待:细粒度地为每个资源都提供一个锁就会导致该问题,破坏并发的一个方式就是重新回到一把锁来管理多个资源的情况,唯一的问题是将两个已经分开的锁合并为一个,就需要轮询直到两个资源都获取到手,合并的粒度可以是原来那个全局唯一的锁;但是,也可以让多个局部资源由一个局部性的单例来管理,局部性越强,效率也就越好,当然,跨域资源的管理依然得需要更广级别的锁。
  2. 不可抢占:Java语言层面的锁synchronized就是不可抢占的
  3. 循环等待:可以规定,按照资源的序号,只能用一种顺序来加锁,这样,等待就变成了抢锁。因为有序的多资源就是一个资源,在我们其实不关心获取资源的先后顺序的情况下,它实现了最恰当好处的粒度;当然,我们也需要在排序消耗与轮询等待消耗之间做选择。

05 等待通知与异步

标签:初始化,极客,Java,对象,编程,加锁,线程,volatile,资源
From: https://www.cnblogs.com/qqiwei/p/17081262.html

相关文章

  • JavaScript学习笔记—DOM:事件
    事件(event)事件就是用户和页面之间发生的交互行为比如:点击按钮,鼠标移动,双击按钮,敲击键盘,松开按键...可以通过为事件绑定响应函数(回调函数),来完成和用户之间的交互绑定响......
  • 学习java第四天
    IDEA安装安装完创建src创建newjava.classIDE快捷键:1.psvm=publicstaticvoidmain(String[]args){ }2.sout=System.out.println();IDE:把ide精益求精JAVA语......
  • Java斐波那契数列实例
      在斐波那契数列中,下一个数字是前两个数字的总和,例如:0,1,1,2,3,5,8,13,21,34,55等。斐波那契数列的前两个数字是0和1,第三个数字是前两个数字的和,也就是0+1=1,所以这......
  • Java素数实例
    质数(primenumber)又称素数,有无限个。质数定义是:在大于1的自然数中,除了1和它本身以外不再有其他因数的数称为质数。例如,2,3,5,7,11,13,17….是素数。注意:0和1不是素数。2是......
  • JAVA--你好世界
    publicclassHello{publicstaticvoidmain(String[]args){System.out.print("你好,世界!");}}D:\code>javacHello.java-->生成.class文件D:\co......
  • Java回文实例
    Java中的回文数定义:回文数是反向后与原数字也是相同的数字(即:从左边读和从右边读过来都是同一个数字)。例如,545,151,3454,343,171,4884都是回文数。实现回文数算法获......
  • Java阿姆斯壮数(armstrongnumber) 实例
    Java中的阿姆斯壮数(armstrongnumber)定义:阿姆斯壮数(armstrongnumber)是等于其数字的立方数之和的数字,例如:0,1,153,370,371,407等。现在试着理解为什么153是一个阿姆斯壮数......
  • Java阶乘实例
    Java中的阶乘程序:n的阶乘是所有正整数的乘积。n的因子由n!来表示。例如:4!=4*3*2*1=245!=5*4*3*2*1=120Java这里,4!发音为“4的阶乘”。阶乘通常用于组......
  • Java插入排序
    下面我们创建一个java程序,实现使用插入排序对数组元素进行排序。插入排序对于小元素是有好处的,因为排序大量元素它需要更多的时间。让我们来看看一个简单的java程序,使......
  • Java选择排序
    在这个示例中,我们创建一个java程序,实现使用选择排序对数组元素进行排序。在选择排序算法中,搜索最低的元素并将其排列到适当的位置。用下一个最小的数字交换当前元素。......