vlambda博客
学习文章列表

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(); // B try { System.out.println(Thread.currentThread().getName()+"=>set"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); // B } }
@Override public 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 {
// 原子引用 CAS AtomicReference<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