JAVA锁之公平锁/非公平锁、可重入锁、自旋锁解读
21、Java锁
java锁系列已经是JUC并发编程整个系列的课程最后一个阶段了,不知道大家学到了吗?如果有收获记得给我留言哦!
1、公平锁非公平锁
公平锁非公平锁
是什么
公平锁:就是非常公平,先来后到
非公平锁:就是非常不公平,可以插队!但是有时候插队可以提高效率 3个小时
public ReentrantLock() {sync = new NonfairSync(); // 默认是非公平锁,随机}public ReentrantLock(boolean fair) { // 公平锁sync = fair ? new FairSync() : new NonfairSync();}
两者区别
公平锁:并发环境下,每个线程在获取到锁的时候都要先看一下这个锁的等待队列!如果为空,那就可以占有锁!否则就要等待!
非公平锁:上来就直接尝试占有该锁!如果失败就会采用类似公平锁的方式!
synchronized :默认就是非公平锁,改不了
ReentrantLock :默认就是非公平锁,可以通过参数修改!
2、可重入锁
可重入锁
递归锁就是可重入锁!
大门 卧室A 卧室B 厕所
白话:线程可以进入任何一个他已经拥有锁的,锁所同步的代码块!
==最大的好处:就是避免死锁!==
练武不练功,到老一场空!
package com.coding.lock;import java.util.function.Predicate;public class RTLock {public static void main(String[] args) {Phone phone = new Phone();new Thread(()->{phone.sendSMS();},"T1").start();new Thread(()->{phone.sendMail();},"T2").start();}}class Phone {public synchronized void sendSMS(){ // 外面的锁System.out.println(Thread.currentThread().getName()+" sendSMS");sendMail(); // 这个方法本来也是被锁的,但是由于获得了外面的锁,所以这个锁也获得了!}public synchronized void sendMail(){System.out.println(Thread.currentThread().getName()+" sendMail");}}
ReentrantLock
package com.coding.lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class RTLock2 {public static void main(String[] args) {Phone2 phone2 = new Phone2();// T1 线程在获得外面锁的时候,也会拿到里面的锁!new Thread(phone2,"T1").start();new Thread(phone2,"T2").start();}}class Phone2 implements Runnable{Lock lock = new ReentrantLock();public void get(){lock.lock(); // A // lock 锁必须匹配!// lock.lock(); // A // lock 锁必须匹配!try {System.out.println(Thread.currentThread().getName()+"=>get");set();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock(); // A}}public void set(){lock.lock(); // Btry {System.out.println(Thread.currentThread().getName()+"=>set");} catch (Exception e) {e.printStackTrace();} finally {lock.unlock(); // B}}@Overridepublic void run() {get();}}
3、自旋锁
自旋锁
自旋锁 spinlock
尝试获取锁的线程不会立即阻塞,采用循环的方式尝试获取锁!减少上下文的切换!缺点会消耗CPU
public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;}
我们手动编写一个锁来测试!
package com.coding.lock;import com.sun.org.apache.bcel.internal.generic.NEW;import java.util.concurrent.atomic.AtomicReference;// coding自己定义的艾编程的锁!public class MyLock {// 原子引用 CASAtomicReference<Thread> atomicReference = new AtomicReference<>();// 加锁public void myLock(){Thread thread = Thread.currentThread();System.out.println(Thread.currentThread().getName()+"==mylock");// 期望是空的没有加锁, thread // 自旋,(循环!)while (atomicReference.compareAndSet(null,thread)){// cas}}// 解锁public void myUnlock(){Thread thread = Thread.currentThread();atomicReference.compareAndSet(thread,null);System.out.println(Thread.currentThread().getName()+"==myUnlock");}}package com.coding.lock;import java.util.concurrent.TimeUnit;public class SpinLockDemo {public static void main(String[] args) {MyLock myLock = new MyLock();new Thread(()->{myLock.myLock();try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}myLock.myUnlock();},"T1").start();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{myLock.myLock();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}myLock.myUnlock();},"T2").start();}}
end
