并发编程理解

 

避免死锁的方法:

1.避免同一个线程同时获取多个锁。2.避免同一个线程在锁内同时占用多个资源,尽量保证一个锁对应一个资源。3.尝试使用定时锁lock.tryLock(timeout)替代内部锁机制。4.数据库的加锁和解锁必须在一个数据库的连接里,否则出现锁失败的情况。

java并发机制实现原理

volitle关键字实现原理(下列原理为缓存一致性机制)

1.CPU的lock指令操作,final int a=1;底层实现干两件事(1)在当前CPU下,将a处于当前CPU缓存行的数据写入到内存中。(2)将其他CPU中缓存的a的数据设置为无效,这样其他CPU获取数据,只能从内存中获取数据。底层实现协议为CPU的MESI协议(为缓存行的几个状态,记为迷死协议,大体实现思想为监听对a内存地址的操作&CPU缓存行的操作)对于旧的CPU是通过直接锁CPU总线的形式,会导致锁定期间其他CPU无法获取内存的数据(即便不是数据a的也无法访问)

synchronized关键字实现原理

synchronized锁优化:

旧的方式:通过操作系统的互斥锁(重量锁)来实现。线程运行到同步代码块的时候,被阻塞线程会由用户态切换到内核态,等锁释放时,激活阻塞线程,频繁的来回切换会导致,系统性能下降。举例:两个线程A、B都要做对i进行累加操作,该操作可能只需要1ms就完成.如果使用重量锁,线程A执行是,线程B进入到内核态,等A执行完后,又要CPU将B切换到用户态,切换过程就可能耗费5ms。如果频繁上下文切换,则严重降低效率。此时如果用轻量锁,B处于自旋状态,会更快。重量锁适合场景:同步块执行时间长(起码比上下文切换时间长)轻量锁适合场景:同步块执行时间短。偏向锁->轻量锁->重量锁的过程偏向锁->轻量锁:一开始认为只有一个线程执行同步代码块,等到出现竞争后,才会升级为轻量锁。轻量锁到重量锁的膨胀体现了对jvm对同步块执行时间的判断,自旋超过一定次数,则认为同步块执行时间长,需要转为重量锁更合适。类似于打仗时的战备状态,一开始是三级战备(对情况乐观),根据情况严重升级战备状态

java对象头

java对象头中包含了锁的状态(锁状态:偏向锁|轻量锁|重量锁)指向线程ID、对象代年龄、GC标识偏向锁:等到竞争出现才会释放锁。如果A线程持有锁,且A线程正在执行,则B线程CAS将对象头的线程ID改为B时,则替换失败。等到A线程到达安全点。(1)如果A线程退出代码块(不再执行),则将对象头标记为无锁状态。(2)A线程仍然执行,则升级为轻量锁。轻量锁:在线程栈中建立锁记录(lock record),用于存储对象头中的数据(复制过来)。然后通过CAS尝试将对象头中的栈指针指向当前线程,失败则开始自旋,成功则拥有该锁,开始执行。失败的线程自旋若干次之后,仍然失败,对象头中的锁需要膨胀为重量锁。

原子操作实现原理

硬件级别:1.总线锁2.缓存锁(缓存一致性协议,MESI)JAVA实现:1.CAS 2.锁机制

java内存模型(JMM)

内存模型基础

线程之间的通信

1.共享内存2.消息传递。java并发采用了共享内存模型。

内存模型的抽象数据结构

JMM定义了线程A定义了共享变量的写入,何时对线程B可见。实际上是通过主内存,共享变量,来实现线程A向线程B发送消息。

源代码到指令重排

源代码->编译器优化重排序->指令级并行重排(属于处理器重排)->内存系统重排(属于处理器重排)->最终执行volitle变量通过JMM的插入内存屏障,禁止指令重排。

happen-before规则 阐述内存可见性

程序顺序规则:一个线程的每个操作,happen-before于线程中的任意后续操作。监视器规则:一个锁的解锁,happen-before于随后对该锁的解锁volitle规则:对一个volitle的写,happen-before于后续的读。传递性。happen-before保证的是先前的操作对后续的操作是可见的。

java的AQS详解

非阻塞算法

非阻塞算法被称为乐观算法

你可能感兴趣的:(java多线程学习)