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