自旋锁
线程无法获取锁时不会被阻塞,而是一直处于忙等状态,不释放CPU资源
排它锁(亦称写锁、独占锁)
线程无法获取锁时将被阻塞,并释放CPU资源,CPU可运行其他线程
可重入锁
可重入锁表示线程获取锁后,在无需释放该锁的情况下可重复获取该锁,不会发生死锁
若为非可重入锁,第二次获取该锁时,该锁由于线程任务未执行完成(尝试第二次获取该锁)而无法释放,导致无法第二次获取该锁,遂发生死锁
需要说明的是,可重入锁与自旋锁、 排它锁并不冲突,synchronized与lock就是可重入排它锁
可重入自旋锁示例:
public class MyLock {
private int count = 0;
public AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void lock(){
Thread thread = Thread.currentThread();//获取当前线程
System.out.println(Thread.currentThread().getName() + " 进入 MyLock.lock()");
//锁已被当前线程获取 进行重复获取(count++)并返回
if (thread == atomicReference.get()){
System.out.println("lock ++");
count ++;
return;
}
//锁已被其他线程获取时 当前线程会在此自旋
while (!atomicReference.compareAndSet(null, thread)){
System.out.println(Thread.currentThread().getName() + " 尝试获取锁");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 成功获取锁");
}
public void unlock(){
Thread thread = Thread.currentThread();//获取当前线程
System.out.println(Thread.currentThread().getName() + " 进入 MyLock.unlock()");
if (thread == atomicReference.get()){
if (count != 0){
System.out.println("lock --");
count--;
} else {
atomicReference.compareAndSet(thread,null);
System.out.println(Thread.currentThread().getName() + " 成功完全解锁");
}
}
}
}
测试代码:
public class Test {
static MyLock lock = new MyLock();
public static void method(){
lock.lock();
lock.lock();
System.out.println("上锁完毕 开始解锁");
lock.unlock();
lock.unlock();
}
public static void main(String[] args) {
Test.method();
}
}
测试结果: