(四)【Java精选面试题】AQS底层架构设计原理(含答案)


1. 谈谈Lock锁底层实现原理

底层基于AQS+Cas+LockSupport锁实现

2. synchronized与lock锁之间区别

Lock基于AQS封装的锁,结合 CAS实现,而Lock锁的升级过程需要自己实现;
Synchronized是基于C++虚拟机封装,JDK1.6优化可以实现锁的升级过程;

3. 谈谈LockSupport的用法

public class Test01 {
	public static void main(String[] args) {
		Thread t1 = new Thread(() -> {
			System.out.println(">>>start<<<");
			//park停止线程
			LockSupport.park();
			System.out.println(">>>end<<<");
		});
		t1.start();
		try {
			Thread.sleep(1000);
		} catch (Exception e) {
		
		}
		// unpark(启动唤醒线程)
		LockSupport.unpart(t1);
	}
}

4. AQS核心参数有哪些呢

1.Node节点采用双线链表的形式存放正在等待的线程waitStatus状态、thread等到锁的线程
CANCELLED,值为1,表示当前的线程被取消;
SIGNAL,值为-1,释放资源后需唤醒后继节点;
CONDITION,值为-2,等待condition唤醒;
PROPAGATE,值为-3,工作于共享锁状态,需要向后传播,比如根据资源是否剩余,唤醒后继节点;
值为0,表示当前节点在sync队列中,等待着获取锁。
1.Head头节点,等待队列的头节点
2.Tail尾结点,正在等待的线程
3.State锁的状态,0无锁、1已经获取锁,当前线程重入不断+1
4.exclusiveOwnerThread记录锁的持有
核心方法:
//充实获取锁,如果小于0的情况则当前线程会追加到链表中
1.tryAcquireShared(arg)
//如果为true的情况下,则开始唤醒阻塞的线程
2.tryReleaseShared(arg)

公平锁实现原理图:
在这里插入图片描述

非公平锁实现原理图:
在这里插入图片描述

5. Lock锁基本实现原理

1.Lock锁原理,基于javaAQS类封装,在获取锁的时候AQS类中有一个状态state+1,当前线程不断重入的时候都会不断+1,当在释放锁的时候state-1;最终state为0该锁没有被任何线程获取到,没有抢到锁的线程,会存在一个双向的链表中。
2.公平锁与非公平锁在获取锁的时候多了一个判断(!hasQueuedPredecessors()&
阻塞和唤醒用的apilocksupport,为了这个效率只会唤醒阻塞队列中head节点.next线程。

public class DemoLock {
	// cas 0表示没有获取锁 1表示获取到锁
	private AtomicInteger atomicState = new AtomicInteger(0);
	// 缓存没有获取锁的线程
	private ConcurrentLinkedDeque<Thread> waitDequeThread = new ConcurrentLinkedDeque<Thread>();
	// 获取锁的线程
	private transient Thread exclusiveOwnerThread;

	public boolean lock() {
		boolean acquire = acquire();
		if (acquire) {
			// 记录获取到锁的线程
			exclusiveOwnerThread = Thread.currentThread();
			return true;
		}
		// 尝试重试策略 最多重试5次
		int i = 0;
		for(;;) {
			if (acquire()) {
				return true;
			}
			i++;
			// 限制最多只能重试5次
			if (i >= 5) {
				// 获取锁失败,则将该线程缓存到链表中
				Thread thread = Thread.currentThread();
				waitDequeThread.add(thread);
				// 当前线程释放cpu执行权
				LockSupport.park();
				return false;
			}
		}
	}

	/**
	* 获取锁
	* @return
	*/
	public boolean acquire() {
		Integer state = getState();
		if (state == 0) {
			// 获取锁
			if (compareAndSet(0, 1)) {
				return true;
			}
			// cas 失败!
			return false;
		}
		return false;
	}

	public void unLock() {
		if (exclusiveOwnerThread != Thread.currentThread()) {
			return;
		}
		// 释放锁
		if (compareAndSet(1, 0)) {
			// 唤醒正在阻塞的第一个线程
			Thread thread = waitDequeThread.peekFirst();
			if (thread != null) {
				LockSupport.unpark(thread);	
			}
			return;
		}
	}

	private boolean compareAndSet(int expect, int update) {
		return atomicState.compareAndSet(expect, update);
	}

	private Integer getState() {
		return atomicState.get();
	}

	public static void main(String[] args) {
		DemoLock demoLock = new DemoLock();
		demoLock.lock();
		System.out.println("test");
		new Thread(() -> {
			demoLock.lock();
			System.out.println(Thread.currentThread().getName() + "我是子线程");
		}).start();	
//		demoLock.unLock();
	}
}

6. Semaphore信号量底层原理

1.Semaphore用于限制可以访问某些资源(物理或逻辑)的线程数目,他维护了一个许可证集合,有多少资源需要限制就维护多少许可证集合,假如这里有N个资源,那就对应于N个许可证,同一时刻也只能有N个线程访问。一个线程获取许可证就调用acquire方法,用完了释放资源就调用release方法。
2.可以简单理解为Semaphore信号量可以实现对接口限流,底层是基于aqs实现
Semaphore简单用法

Semaphore semaphore = new Semaphore(5);
for (int i = 0; i < 6; i++) {
	new Thread(() -> {
		try {
			// 获取凭证 状态-1
			semaphore.acquire();	
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ",抢到了凭据");
		try {
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName() + ",释放凭据");
			// 状态+1
			semaphore.release();	
		} catch (Exception e) {}
	}).start();	
}

Semaphore工作原理

  1. 可以设置Semaphore信号量的状态state值为5
  2. 当一个线程获取到锁的情况下,将state-1,释放成功之后state+1
  3. 当state<0,表示没锁的资源,则当前线程阻塞。

7. CountDownLatch底层原理

CountDownLatch源码分析
CountDownLatch是一种java.util.concurrent包下一个同步工具类,它允许一个或多个线程等待直到在其他线程中一组操作执行完成。和join方法非常类似
CountDownLatch底层是基于AQS实现的
CountDownLatch countDownLatch = new CountDownLatch(2)AQS的state状态为2
调用countDownLatch.countDown();方法的时候状态-1,当AQS状态state为0的情况下,则唤醒正在等待的线程。

public static void main(String[] args) {
	CountDownLatch countDownLatch = new CountDownLatch(1);
	new Thread(() -> {
		try {
			System.out.println("t1开始执行..");	
			countDownLatch.await();
			System.out.println("t1结束执行..");
		} catch (InterruptedException e) {
			e.printStackTrace();	
		}
	}, "t1").start();
	countDownLatch.countDown();
	countDownLatch.countDown();
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级码里喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值