java进阶之并发编程一ReentrantLock同步锁的学习和syncthronized的区别

引言:随着JAVA EE商业化的推广,面对技术复杂的并发需求显得力不从心,为了满足开发者的需求,JDK版本也逐步更新,在推出的JDK1.5中引入并发编程工具包java.util.concurrent,该包对并发场景有着更良好的api支持。

本文主要介绍同步锁syncthronized的替代方案ReentrantLock的概念和API介绍

java.util.concurrent.locks.Lock  :使用lock可获得更灵活的结构和同步属性解决方案;

java.util.concurrent.locks.ReentrantLock:lock的实现类,可实现重入,公平的互斥锁,拥有比syncthronized更灵活高效的功能;

java.util.concurrent.locks.Condition:提供于lock锁的监控,一个锁可以有多个Condition实例,相当于Object的监控;

一:首先介绍下syncthronized:
syncthronized是java jvm中的一个保留关键字,可以实现同步的作用,

它可以修饰在方法上,也可以修饰在具体代码,被它修饰的代码块或方法在同一时刻只能有一个线程运行。

它相对于属于悲观锁,将当前抢占到锁的线程设为独占线程,未抢到锁的其他线程为阻塞状态,确保同步状态。

syncthronized和ReentrantLock的区别;

syncthronized是基于这个关键字加锁的,ReentrantLock是基于其api方法加锁的,syncthronized是自动释放锁的,Reentrant需要手动释放,在业务编写中ReentrantLock一般在try{}finally{}中搭配使用的,避免锁的释放。

syncthronized属于悲观锁方式,是阻塞式的,采用独占的方式,每次获取和释放锁频繁,上下文资源切换较大,存在短暂调度延迟。

ReentrantLock属于乐观锁思想,是非阻塞式的,是轻量级的,其内部的CAS就是基于乐观锁的思想实现的,CAS是建立在硬件指令集中的,是通过指令切换来达到原子性,比锁的切换是要快很多的,CAS中有三个参数,内存变量地址A,预期值B,要更新的值C,当多个线程想要更新CAS的内存变量值时会进行判断,若当前CAS内存地址指向B,则将C更新为A,若当前A指向不是预期的B,则线程更新失败,失败的线程不会被挂起,会重新准备再次尝试更新。

二:介绍ReentrantLock的常用API;

ReentrantLock是Lock的子类继承接口,拥有比Lock更强大的功能,拥有互斥,可重入性, 可中断性,是否公平性。在复杂的并发业务需求上拥有比syncthronizd更灵活的结构, 提供更强大的API支持。   

ReentrantLock的几个重要方法:        

ReentrantLock(boolean fair); 是否为公平锁;

Condition newCondition(); 返回一个该锁Condition实例;

void lock(); 获取锁;

void lockInterruptibly(); 在当前线程未被中断的情况下获取锁;

boolean tryLock();当前锁未被其他线程持有时获取锁;

void unlock();释放锁;

boolean isHeldbyCurrentThread();当前线程是否持有该锁;

二:介绍Condition常用API

Condition充当ReentrantLock的辅助监控责任,将Object的监控(wait,notify)分解成继而不同的对象,从而更方便的对lock的实现

其 await和sginal()和Object的wait和notify相识,不同的是 一个lock可实现多个Condition,

await(); 造成当前线程在被中断和释放前一直处于等待状态。

signal();随机唤醒一个等待的线程。

signAll();唤醒所有等待的线程。

::其中Sinal和unlock的先后顺序在不同的业务应用上也颇为重要。

后续:

demo1:

有这么一个应用场景,有A,B,C三个线程,

实现 A打印3次,B线程接着打印3次,C线程再打印三次,使用ReentrantLock和Condition实现。

demo2:

模仿一个线程死锁,使用ReentrantLock进行线程中断。

猜你喜欢

转载自blog.csdn.net/msdengxw/article/details/81206771