1、公平锁、非公平锁
公平锁:非常公平,不能插队,先来后到
非公平锁(默认):非常不公平,可以插队
比如:有一个线程需要3s执行结束,另一个3h执行结束,但3h先到。那么对于公平锁,3s必须等3h执行完毕,而对于非公平锁就可以让3s先插队执行。
如上,默认都是非公平,synchronized 和Lock都是默认非公平
2、可重入锁
可重入锁又称递归锁
假设我们进自己家需要一把大门锁,然后拿到大门锁,自然就可以进房间里面
代码演示一下
package com.yx.lock;
public class demo01 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sms();
},"A").start();
}
}
class Phone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName() + "sms");
call();//这里也有锁
}
public synchronized void call(){
System.out.println(Thread.currentThread().getName() + "call");
}
}
线程A调用sms方法时,首先会给sms加锁,然后打印sms,进入call中,自动拿到call的锁,并call打印后,最后再释放所有锁,也就是拿到外面的锁就会自动拿到里面的锁,最后执行完所有的内容,释放锁。
这里用的是synchronized ,我们来看看Lock锁对比一下
3、自旋锁
自旋就是循环,加了一个while语句或者do…while语句。我们来自己实现一个自旋锁,然后用它进行加锁解锁
package com.yx.lock;
import java.util.concurrent.atomic.AtomicReference;
//CAS(CompareAndSet)实现自旋锁
public class SpinLockDemo {
AtomicReference<Thread> atomicReference = new AtomicReference<>();
//加锁
public void myLock(){
Thread thread = Thread.currentThread();//当前线程
System.out.println(Thread.currentThread().getName()+"->myLock");
//不成立就一直循环自旋
while (!atomicReference.compareAndSet(null,thread)){
}
}
//解锁
public void myUnLock(){
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"->myUnLock");
atomicReference.compareAndSet(thread,null);
}
}
运行下面方法
package com.yx.lock;
import java.util.concurrent.TimeUnit;
public class TestSpinLock {
public static void main(String[] args) throws InterruptedException {
SpinLockDemo lock = new SpinLockDemo();
new Thread(()->{
lock.myLock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.myUnLock();
}
},"T1").start();
TimeUnit.SECONDS.sleep(1);//保证T1线程先拿到锁
new Thread(()->{
lock.myLock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.myUnLock();
}
},"T2").start();
}
}
分析:首先T1线程拿到锁,进入自旋,然后T2也拿到锁,5秒后T1解锁跳出自旋,T2也跟着解锁。注意这个执行的顺序