前言:当我第一次看到这个标题时,感觉“很熟悉,但又很陌生”,因为锁是有效解决并发情况下关键资源操作原子性的有效手段之一。下面我就从我们开发使用的几个角度来说说我们常用的锁。锁能解决什么问题?锁可以解决任务并行执行时顺序访问和修改共享数据的场景。例如,平行扣除或转入同一账户。让我们在下面讨论synchronized、ReetranLock和它们的使用。SynchronizedSynchronized是JDK提供的内置锁。它由JVM虚拟机实现,基于监控机制。在JDK1.6之后进行了优化。会有一个锁升级过程,将锁的状态存储在对象头中。在锁升级过程中,默认是无锁状态。首先,将作出判断。如果没有现场比赛,就会使用偏向锁。偏向锁的本质是将当前获取锁的线程id设置为共享数据的对象头。然后升级为轻量级锁。轻量级锁的本质是通过CAS修改MarkWord。最后可以升级为重量级锁,我们可以通过操作系统的监听来实现,依赖操作系统的MutexLock(互斥锁)。四种使用方式UseonstaticmethodsUseon普通方法LockthisstateLockstaticclasslockstate记录对象锁的位置,记录在对象头中,对象头如下图所示。在运行过程中,MarkWord中存储的数据会随着锁定标志位的变化而变化。MarkWord可以存储以下4种类型的数据。如下图所示,锁升级扩容时,锁扩容升级是不可逆的。JDK中concurrent包中,使用synchroinzed的地方有:ConcurrentHashMap(jdk1.8)HashTableReetrantLockReetrantLock是由DougLea开发的,从JDK1.5开始,加入了JDK锁,主要是通过QAS的方式,通过Unsafe包的提供CAS操作用于锁状态竞争。然后通过LockSupport.park(this)停放线程。如果AQS队列头部的对象被唤醒,执行了unpack方法,那么就让他去竞争锁。ReetrantLock也分为公平锁和非公平锁,默认是非公平锁。因为公平锁需要保证竞争者按照获取锁的顺序获取锁,所以性能比非公平锁略低。AQS队列结构如下图所示。它本质上是一个先进先出的线程安全同步队列,如下图所示:ReetrantLock加锁和解锁的过程如下图所示:用法ReetrantLock的使用方法如下,主要分三步:创建,加锁,解锁。classX{privatefinalReentrantLocklock=newReentrantLock();//...publicvoidm(){lock.lock();//blockuntilconditionholdstry{//...methodbody}finally{lock.unlock()}}}在并发包中使用场景JDK其中用到ReetrantLock的地方有:CyclicBarrierDelayQueueLinkedBlockingDequeThreadPoolExecutorReentrantReadWriteLockStampedLock我只是列举了一部分。对于ReetrantLock,可以说是concurrent包中一个非常基础的类,也是我们学习并发的基础。在后续的文章中,我会对展开做更深入的分析。如何选择锁具?1、对于单机环境,我们在JDK中进行并发控制,可以使用synchronized(内置锁)和RentrantLock。2、对于自增或者原子数据累加,我们可以使用Unsafe提供的原子类,比如AtomicInteger和AtomicLong3。对于数据库,我们可以使用乐观锁来控制用户扣款的场景。SQL如下:updatetable_namesetamount=100,version=version+1whereid=1andversion=1;4.对于分布式场景,我们需要保证一致性,可以使用Redis或者Zk来实现分布式锁。在分布式场景下进行并发控制。参考资料《深入理解 Java 虚拟机》周志明https://blog.csdn.net/wangbo199308/article/details/108688109【小编推荐】苹果推送iOS15正式版更新内容通知抛顶姐牛-图解MySQL8.0优化器查询解析文章轻松SQL三注入威胁的方法iPhone13即将推出iOS还要忍受这些缺陷多久?为什么现在手机越来越贵了?
