网站建设需要注意哪些事项,张掖市作风建设年活动网站,建设企业营销型网站,seo网络优化平台锁定义和特征 乐观锁 VS 悲观锁
区别 乐观锁不会添加锁#xff0c;无锁算法#xff0c;没有线程被阻塞。悲观锁拿到资源就加锁#xff0c;线程被阻塞。 乐观锁#xff1a;CAS算法 Compare-And-Swap#xff08;比较并交换#xff09;的缩写,轻量级锁。 Java中#xff…锁定义和特征 乐观锁 VS 悲观锁
区别 乐观锁不会添加锁无锁算法没有线程被阻塞。悲观锁拿到资源就加锁线程被阻塞。 乐观锁CAS算法 Compare-And-Swap比较并交换的缩写,轻量级锁。 Java中synchronized关键字和Lock的实现类都是悲观锁。 乐观锁适合读操作多的场景悲观锁适合写操作多的场景 CAS算法
CAS全称 Compare And Swap比较与交换是一种无锁算法。在不使用锁没有线程被阻塞的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。
CAS算法涉及到三个操作数 需要读写的内存值 V。 进行比较的值 A。 要写入的新值 B。
当且仅当 V 的值等于 A 时CAS通过原子方式用新值B来更新V的值“比较更新”整体是一个原子操作否则不会执行任何操作。 自旋锁 VS 适应性自旋锁
自旋锁本身是有缺点的它不能代替阻塞。自旋等待虽然避免了线程切换的开销但它要占用处理器时间。如果锁被占用的时间很短自旋等待的效果就会非常好。反之如果锁被占用的时间很长那么自旋的线程只会白浪费处理器资源。所以自旋等待的时间必须要有一定的限度如果自旋超过了限定次数默认是10次可以使用-XX:PreBlockSpin来更改没有成功获得锁就应当挂起线程 自适应意味着自旋的时间次数不再固定而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上自旋等待刚刚成功获得过锁并且持有锁的线程正在运行中那么虚拟机就会认为这次自旋也是很有可能再次成功进而它将允许自旋等待持续相对更长的时间。如果对于某个锁自旋很少成功获得过那在以后尝试获取这个锁时将可能省略掉自旋过程直接阻塞线程避免浪费处理器资源。
无锁 VS 偏向锁 VS 轻量级锁 VS 重量级锁
Java对象头Monitor
synchronized是悲观锁在操作同步资源之前需要给同步资源先加锁这把锁就是存在Java对象头里的 无锁
CAS
偏向锁 偏向锁是指一段同步代码一直被一个线程所访问那么该线程会自动获取锁降低获取锁的代价。 当一个线程访问同步代码块并获取锁时会在Mark Word里存储锁偏向的线程ID。如果Mark Word有当前线程的ThreadID,直接获取资源不需要执行CAS。出现其他线程尝试竞争偏向锁时持有偏向锁的线程才会释放锁到无锁或者轻量级锁。 轻量级锁 是指当锁是偏向锁的时候被另外的线程所访问偏向锁就会升级为轻量级锁其他线程会通过自旋的形式尝试获取锁不会阻塞 若当前只有一个等待线程则该线程通过自旋进行等待。但是当自旋超过一定的次数或者一个线程在持有锁一个在自旋又有第三个来访时轻量级锁升级为重量级锁。
重量级锁
升级为重量级锁时锁标志的状态值变为“10”此时Mark Word中存储的是指向重量级锁的指针此时等待锁的线程都会进入阻塞状态 公平锁 VS 非公平锁
公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁线程直接进入队列中排队队列中的第一个线程才能获得锁。
优点是等待锁的线程不会饿死。
缺点是整体吞吐效率相对非公平锁要低等待队列中除第一个线程以外的所有线程都会阻塞CPU唤醒阻塞线程的开销比非公平锁大。 非公平锁
非公平锁是多个线程加锁时直接尝试获取锁获取不到才会到等待队列的队尾等待。但如果此时锁刚好可用那么这个线程可以无需阻塞直接获取到锁所以非公平锁有可能出现后申请锁的线程先获取锁的场景。非公平锁的优点是可以减少唤起线程的开销整体的吞吐效率高因为线程有几率不阻塞直接获得锁CPU不必唤醒所有线程。缺点是处于等待队列中的线程可能会饿死或者等很久才会获得锁。 ReentrantLock
ReentrantLock里面有一个内部类SyncSync继承AQSAbstractQueuedSynchronizer添加锁和释放锁的大部分操作实际上都是在Sync中实现的。它有公平锁FairSync和非公平锁NonfairSync两个子类。ReentrantLock默认使用非公平锁也可以通过构造器来显示的指定使用公平锁。 可重入锁 VS 非可重入锁
可重入锁又名递归锁是指在同一个线程在外层方法获取锁的时候再进入该线程的内层方法会自动获取锁前提锁对象得是同一个对象或者class不会因为之前已经获取过还没释放而阻塞。Java中ReentrantLock和synchronized都是可重入锁可重入锁的一个优点是可一定程度避免死锁。下面用示例代码来进行分析 源码分析
之前我们说过ReentrantLock和synchronized都是重入锁那么我们通过重入锁ReentrantLock以及非可重入锁NonReentrantLock的源码来对比分析一下为什么非可重入锁在重复调用同步资源时会出现死锁。
首先ReentrantLock和NonReentrantLock都继承父类AQS其父类AQS中维护了一个同步状态status来计数重入次数status初始值为0。
当线程尝试获取锁时可重入锁先尝试获取并更新status值如果status 0表示没有其他线程在执行同步代码则把status置为1当前线程开始执行。如果status ! 0则判断当前线程是否是获取到这个锁的线程如果是的话执行status1且当前线程可以再次获取锁。而非可重入锁是直接去获取并尝试更新当前status的值如果status ! 0的话会导致其获取锁失败当前线程阻塞。 可重入锁即进入一次线程status1退出一次status-1,当status减到1说明线程结束。进入doSomething() status 1 1 ,进入doOthers() status 1 2,退出doOthers()status-1 1, 退出doSomething() status -1 0,线程结束。 不可重入锁进入doSomething() status 1 1叫它线程A ,进入doOthers() 之前需要释放线程A持有的锁但是此时锁已经被线程A当前线程持有无法释放造成死锁。 释放锁时可重入锁同样先获取当前status的值在当前线程是持有锁的线程的前提下。如果status-1 0则表示当前线程所有重复获取锁的操作都已经执行完毕然后该线程才会真正释放锁。而非可重入锁则是在确定当前线程是持有锁的线程之后直接将status置为0将锁释放。 独享锁 VS 共享锁
独享锁也叫排他锁是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排它锁后则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。JDK中的synchronized和JUC中Lock的实现类就是互斥锁。
共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后则其他线程只能对A再加共享锁不能加排它锁。获得共享锁的线程只能读数据不能修改数据。
独享锁与共享锁也是通过AQS来实现的通过实现不同的方法来实现独享或者共享。