欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java锁相关知识

程序员文章站 2022-11-22 12:23:38
1. 锁的分类 Java中目前存在几大类型的锁 - 公平锁/非公平锁:是否按照访问的顺序获取锁。 - 共享锁/独占锁:共享锁可允许多个线程持有,例如读写锁中的读锁。独占锁只允许一个线程占有。 - 可重入锁/不可重入锁:针对同一个线程,是否能重复加锁。在函数互调的时候容易出现。 - 乐观锁/悲观锁:乐 ......

1. 锁的分类

 java中目前存在几大类型的锁

 - 公平锁/非公平锁:是否按照访问的顺序获取锁。

 - 共享锁/独占锁:共享锁可允许多个线程持有,例如读写锁中的读锁。独占锁只允许一个线程占有。 

 - 可重入锁/不可重入锁:针对同一个线程,是否能重复加锁。在函数互调的时候容易出现。

 - 乐观锁/悲观锁:乐观锁的执行流程是:操作前不会加锁,在更新的时候通过版本号和cas来判断是否能执行,适合读多写少的的情况。例如mysql的mvvc。

          悲观锁的执行流程是:操作前必须先获取到锁然后才能进行操作。

 - 条件锁/读写锁:lock.condition,需要满足条件(sinal)才能解锁。读写锁:lock下实现的,其中有读锁和写锁(读读可以,其他只允许一个线程执行),乐观锁。

 ps: cas是通过while循环不断的自旋尝试修改,比较适合锁的时间比较短的场景。

 

2. 锁的理解

 比较通俗的理解就是,锁是相当于临界区的钥匙,当然有不同的锁,不同的钥匙。

 

3. lock和synchronized的区别

 - lock是接口,是jdk层面的。synchronized是java关键字,是jvm层面的。

 - synchronized可以实现自动释放锁,有完善的解锁机制。lock必须手动解锁。

 - lock提供了接口支持锁的状态判断,synchronized不支持。

 - synchronized是独占锁,无法获取锁的线程会堵塞。lock中可以通过trylock判断是否有线程占用了锁,可以防止堵塞

 - synchronized的底层(字节码)是通过monitorenter和monitorexit实现加锁和解锁。lock底层则是通过aqs和cas实现的。

 - synchronized是非公平,独占,可重入的,不可中断。 lock是可公平/非公平,可重入,可中断的。
 ps: aqs=队列+cas

 

4. 锁在java的数据结构中的运用

 1. hashtable: 所有函数都是加了synchronized的,因此是线程安全的,没啥好分析的,性能当然也比较差。

 2. vector:和arraylist不同,是线程安全的。也是通过synchronized实现。

 3. copyonwritearraylist(copyonwritearrayset):读不需要加锁(通过array.copyof直接改变内部map的引用,浪费内存),写是通过reentrantlock加锁实现的线程安全。在读多写少的场景可以大大提升效率。

 4. concurrentlinkedqueue:高效的并发队列,源码解析将在后续整理。通过cas和"wait-free"算法实现

 5. concurrenthashmap:不同于hashtable的加锁方式,在jdk1.7的时候是采用的分段锁的方式大大减少了锁竞争,一个segment里面有一个hash表。采用链表解决hash冲突。在jdk1.8以后采用cas+synchronized锁住node的形式(看看guava的缓存实现方式),同时在同一个node下冲突的节点数量超过阈值则会转化成红黑树,减少查找的时间复杂度。

 ps: concurrenthashmap这种解决并发的算法和思想很值得在工作中借鉴和运用,也是用来考研一个人对于并发的理解深度。

====================================to be continue========================================