发布于2022-07-08
ReentrantLock
看上一篇的AQS源码深度解读
ReentrantReadWriteLock
它的含义和作用
『读写锁ReentrantReadWriteLock』并不是真正意义上的读写分离,它只允许读读共存,而读写和写写依然是互斥的,大多实际场景是“读/读”线程间并不存在互斥关系,只有"读/写"线程或"写/写"线程间的操作需要互斥的。因此引入ReentrantReadWriteLock。
一个ReentrantReadWriteLock同时只能存在一个写锁但是可以存在多个读锁,但不能同时存在写锁和读锁,只有在读多写少情境之下,读写锁才具有较高的性能体现.
代码示例
注意 读写锁有一个问题就是读线程没有完成读的时候 写线程是一直写不进去的,高并发下可能会有写线程处于锁饥饿的状态
static Map<Integer, String> map = new HashMap<>();
static {
map.put(1, "1");
map.put(2, "2");
map.put(3, "3");
map.put(4, "4");
map.put(5, "5");
map.put(6, "6");
map.put(7, "7");
map.put(8, "8");
map.put(9, "9");
map.put(10, "10");
map.put(0, "0");
}
static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public static void write(Integer key, String value) {
lock.writeLock().lock();
try {
map.put(key, value);
System.out.println("写进去了值:" + map.get(key));
} finally {
lock.writeLock().unlock();
}
}
public static void read(Integer key) throws InterruptedException {
lock.readLock().lock();
try {
//TimeUnit.MILLISECONDS.sleep(4000);
System.out.println("读取出来了值:" + map.get(key));
} finally {
lock.readLock().unlock();
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
try {
read(finalI);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, "read" + i).start();
}
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
write(finalI, String.valueOf(finalI + 10));
}, "read" + i).start();
}
}
读写锁的锁降级
在规定的操作步骤下,写锁是可以自动降级为读锁的,步骤如下
遵循获取写锁→再获取读锁→再释放写锁的次序,写锁能够降级成为读锁。
就是说一个线程占有了写锁,在不释放写锁的情况下,它还能占有读锁,这时候写锁就直接降级为读锁,此时其他的读锁也可以实时读取到数据.他的目的就是为了让当前的所有读线程感知到数据的变化,目的是保证数据可见性
代码示例:
public static void main(String[] args)
{
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
System.out.println("-------正在写入");
readLock.lock();
System.out.println("-------正在读取");
writeLock.unlock();
}
读写锁总结
ReentrantReadWriteLock本质上是一种悲观锁,如果有线程正在读,写线程需要等待读线程释放锁后才能获取写锁,ReadWriteLock读的过程中不允许写,只有等待线程都释放了读锁,当前线程才能获取写锁,也就是写入必须等待,这是一种悲观的读锁.
官方锁降级示例代码:
- 代码中声明了一个volatile类型的cacheValid变量,保证其可见性。
- 首先获取读锁,如果cache不可用,则释放读锁,获取写锁,在更改数据之前,再检查一次cacheValid的值,然后修改数据,将cacheValid置为true,然后在释放写锁前获取读锁;此时,cache中数据可用,处理cache中数据,最后释放读锁。这个过程就是一个完整的锁降级的过程,目的是保证数据可见性。
如果违背锁降级的步骤
如果当前的线程C在修改完cache中的数据后,没有获取读锁而是直接释放了写锁,那么假设此时另一个线程D获取了写锁并修改了数据,那么C线程无法感知到数据已被修改,则数据出现错误。
如果遵循锁降级的步骤
线程C在释放写锁之前获取读锁,那么线程D在获取写锁时将被阻塞,直到线程C完成数据处理过程,释放读锁。这样可以保证返回的数据是这次更新的数据,该机制是专门为了缓存设计的。
StampedLock邮戳锁
定义解释
StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWriteLock的优化,也称之为票据锁.
它内部有一个stamp(戳记,long类型),代表了锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。
解决痛点
他是为了解锁读写锁会导致写线程锁饥饿的问题而推出来的,读写锁的写线程锁饥饿可以使用公平锁一定程度上的缓解,但是就牺牲掉了系统的吞吐量,所以StampedLock横空出世.
使用特点
- 所有获取锁的方法,都返回一个邮戳(Stamp),Stamp为零表示获取失败,其余都表示成功;
- 所有释放锁的方法,都需要一个邮戳(Stamp),这个Stamp必须是和成功获取锁时得到的Stamp一致;
- StampedLock是不可重入的,危险(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)
StampedLock有三种访问模式
- Reading(读模式):功能和ReentrantReadWriteLock的读锁类似
- Writing(写模式):功能和ReentrantReadWriteLock的写锁类似
- Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式
代码示例:
static int number = 37; static StampedLock stampedLock = new StampedLock(); public void write() { long stamp = stampedLock.writeLock(); System.out.println(Thread.currentThread().getName()+"\t"+"=====写线程准备修改"); try { number = number + 13; }catch (Exception e){ e.printStackTrace(); }finally { stampedLock.unlockWrite(stamp); } System.out.println(Thread.currentThread().getName()+"\t"+"=====写线程结束修改"); } //悲观读 public void read() { long stamp = stampedLock.readLock(); System.out.println(Thread.currentThread().getName()+"\t come in readlock block,4 seconds continue..."); //暂停4秒钟线程 for (int i = 0; i <4 ; i++) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"\t 正在读取中......"); } try { int result = number; System.out.println(Thread.currentThread().getName()+"\t"+" 获得成员变量值result:" + result); System.out.println("写线程没有修改值,因为 stampedLock.readLock()读的时候,不可以写,读写互斥"); }catch (Exception e){ e.printStackTrace(); }finally { stampedLock.unlockRead(stamp); } } //乐观读 public void tryOptimisticRead() { long stamp = stampedLock.tryOptimisticRead(); //先把数据取得一次 int result = number; //间隔4秒钟,我们很乐观的认为没有其他线程修改过number值,愿望美好,实际情况靠判断。 System.out.println("4秒前stampedLock.validate值(true无修改,false有修改)"+"\t"+stampedLock.validate(stamp)); for (int i = 1; i <=4 ; i++) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"\t 正在读取中......"+i+ "秒后stampedLock.validate值(true无修改,false有修改)"+"\t" +stampedLock.validate(stamp)); } if(!stampedLock.validate(stamp)) { System.out.println("有人动过--------存在写操作!"); //有人动过了,需要从乐观读切换到普通读的模式。 stamp = stampedLock.readLock(); try { System.out.println("从乐观读 升级为 悲观读并重新获取数据"); //重新获取数据 result = number; System.out.println("重新悲观读锁通过获取到的成员变量值result:" + result); }catch (Exception e){ e.printStackTrace(); }finally { stampedLock.unlockRead(stamp); } } System.out.println(Thread.currentThread().getName()+"\t finally value: "+result); } public static void main(String[] args) { StampedLockDemo resource = new StampedLockDemo(); //3 乐观读,失败,重新转为悲观读,重读数据一次 new Thread(() -> { //乐观读 resource.tryOptimisticRead(); },"readThread").start(); //2秒钟乐观读取resource.tryOptimisticRead()失败 try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { resource.write(); },"writeThread").start(); }
StampedLock读的过程中也允许获取写锁介入,但是乐观读取到的票据很有可能已经被写锁改动过了,我们需要校验一下,如果被改动过,在转换为悲观读的模式再去重新读取改动过后的数据
邮戳锁的缺点
- StampedLock 不支持重入,没有Re开头
- StampedLock 的悲观读锁和写锁都不支持条件变量(Condition),这个也需要注意。
- 使用 StampedLock一定不要调用中断操作,即不要调用interrupt() 方法
Natalieay fotballdrakter LoganBisc MarshaGop brasil VM Drakt RobinMulv AlizaBeeb mexico VM tröja PhilippDo Kenbahpg real madrid trøjer ManieRabi EleanorLy VM fotbollstrojör VM BernardoE AguedaDun maglia atalanta 2023 CornellSi BeatrisAt coutinho drakt barn Jonnautxv ShelleyFa manchester united tøj PenelopeV DaltonPoi frankrike VM Drakt Linwoodil UlrikeMej fotballdrakter AmyPanton OsvaldoRi arsenal trøje RichieBon GaleLower chelsea drakt FlynnChun CarmeloWi Maglia Chile Mondiali 2022 RosaPanne MabelWind leeds drakt GlindaSer MariaStol maglia italia portiere Beulahyxy SusieMich marseille tröja TraceyMew AguedaDun maglia atalanta 2023 CornellSi CheriRoth arsenal trøje MonteBall Lashawnda manchester united tröja barn GarryKerr Torstenib Kroatien VM 2022 Landsholdstrøje ArielleHa
Ramonitah albanien VM Drakt SteveCawt CaraCastl Maglia Brazil Mondiali 2022 BellaMoul DedraHjee osterrike VM Drakt WoodrowSt EmeryStac Maglia Mexico Mondiali 2022 JaredWess CaraCastl Maglia Brazil Mondiali 2022 BellaMoul OdellWayl psg trøje børn HalinaDup Raymundoq nigeria VM 2022 Drakt Demetrius CathrynHw VM fotbollstrojör VM Maximoffd BeulahMer real madrid fodboldtøj BreannaHo WilsonmtF sydkorea VM tröja DZIEmely CrystalDr maglia manchester united 2023 BarbaraIv AltaLawle maglie svizzera ChiSatter MariaTrap kroatia VM 2022 Drakt AudraSumm NicoleDos polen VM tröja JosefamgH ToniaciY Maglia Slovenia Mondiali 2022 LudieCunn MerrillRe OLKTreydx PrestonBo juventus trøje børn DelBloomf Hannelore psg tröjor LloydFais Temekazlr Maglia Slovenia Mondiali 2022 Rebbecacs StewartBl Maglia Belarus Mondiali 2022 Alexandra
你大概是什么步骤能描述一下吗?设置了nginx的静态链接了吗?
Araofclmh australia vm barn Drakt KaseyTls Kristieif real madrid drakt ThadHilly RhysHorns liverpool tröja barn DedraNett AlissaGal Maglia Chile Mondiali 2022 MilanFait OnitaSass chelsea drakt AlannahEa NaomiLev liverpool tröja barn JuanTregu AdrieneBe Brasilien VM 2022 Landsholdstrøje MilfordNe SimonJsh maglie napoli 2022 JuliaLayt EzraPouli marseille tröja LinoldDi JannieSpr chelsea matchtröja GlendaMes CraigTasm Atalanta Drakt LenaBella LashondaB Maglia Armenia Mondiali 2022 JermaineE RicoLeona danmark VM tröja Shananwsw Gildaohft VM fotbollstrojör VM CaryBrans TrenavcZ Portugal VM 2022 Landsholdstrøje JewelJano Jacquetta Island VM 2022 Landsholdstrøje FreyaYdyr TobiasHer Portugal VM 2022 Landsholdstrøje AzucenaVe BeatriceV australia VM 2022 Drakt VeronaTul MoseButtr Maglia Wales Mondiali 2022 StacyHytt TobiasHer Portugal VM 2022 Landsholdstrøje AzucenaVe
我发现我的评论功能,加载不了头像!朋友圈和相册也加载不了,音乐播放器也不显示,求解!