公平锁 & 非公平锁
-
公平锁
公平锁是指多个线程按照申请锁的顺序来获取,先来先得。在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列。如果为空,或者当前线程是等待队列的第一个,就占有锁,佛则就加入到等待队列中,按照 FIFO 的规则取出。
-
非公平锁
非公平锁是指在多线程获取锁的顺序并不是按照申请锁的顺序,而是一种抢占式的方式来获取锁。
synchronized,ReentrantLock 都是一种非公平锁。 但是ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或者非公平锁 默认是非公平锁。
可重入锁(递归锁)
指的是同一个线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码。在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
也就是说:线程可以进入到任何一个它已经拥有锁同步的代码块中。
作用:最大作用就是防止死锁,因为多层嵌套的锁,其实锁的是同一个对象,另一个含义就是:嵌套方法持有的是【同一把锁】。
- 演示 synchronized 可重入锁
public class ReentrantLockDemo {
private int x = 1;
public static void main(String[] args) {
ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
for(int i = 0;i<30;i++) {
new Thread(() -> {
reentrantLockDemo.set();
}, "t1").start();
}
}
public synchronized void set(){ // 获取锁
x = x+1;
get();
}
public synchronized void get(){
System.out.println(x);
}
}
- 演示 ReentrantLock 可重入锁
public class ReentrantLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
Thread t3 = new Thread(phone);
Thread t4 = new Thread(phone);
t3.start();
t4.start();
}
}
class Phone implements Runnable{
private Lock lock = new ReentrantLock();
@Override
public void run() {
get();
}
private void get() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t" + "get");
set();
}finally {
lock.unlock();
}
}
private void set() {
lock.lock();
try{
System.out.println(Thread.currentThread().getName() + "\tset");
}finally {
lock.unlock();
}
}
}
自旋锁
自旋锁是指尝试获取锁的线程不会立即阻塞,而是 采用循环的方式尝试获取锁,这样的好处是可以减少线程上下文切换,但是自循环会导致消耗 CPU 资源。
public class SpinLockDemo {
// 原子对象
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void myLock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "\t"+" come");
while (!atomicReference.compareAndSet(null,thread)){
//自旋
}
}
public void myUnLock(){
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread,null);
System.out.println(Thread.currentThread().getName()+"\t"+ " invoked myUnLock");
}
public static void main(String[] args) {
SpinLockDemo spinLockDemo = new SpinLockDemo();
new Thread(()->{
spinLockDemo.myLock();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"AA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
spinLockDemo.myUnLock();
},"BB").start();
}
}
独占锁 & 共享锁
独占锁:锁每次只能被一个线程所持。synchronized,ReentrantLock 都是独占锁。
共享锁:锁可以被多个线程所有,ReentrantReadWriteLock 的【读锁是共享锁,写锁是独占锁。】
public class ReentrantLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for(int i= 1; i<=5;i++){
final int tmpInt = i;
new Thread(()->{
myCache.put(tmpInt+"",tmpInt+"");
},i+"").start();
}
for(int i=1;i<=5;i++){
final int tempInt = i;
new Thread(()->{
myCache.get(tempInt+"");
},String.valueOf(i)).start();
}
}
}
class MyCache{
private volatile Map<String,Object> map = new HashMap();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void put(String key,Object value){
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName()+"\t"+"正在写入");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t" + "写入完成");
}finally {
lock.writeLock().unlock();
}
}
public void get(String key){
lock.readLock().lock();
System.out.println(Thread.currentThread().getName()+"\t 正在读取:"+key);
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Object result = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读取完成" + "\t" + result);
}finally {
lock.readLock().unlock();
}
}
}

本文详细解析了Java中的锁机制,包括公平锁与非公平锁的区别,可重入锁的实现原理,自旋锁的工作机制,以及独占锁与共享锁的概念。通过代码示例,展示了synchronized关键字和ReentrantLock类如何实现可重入锁,自旋锁的实现方式,以及ReentrantReadWriteLock如何区分读锁和写锁。

1451

被折叠的 条评论
为什么被折叠?



