栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java面试题之synchronized平台级锁和Lock实现的锁区别

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java面试题之synchronized平台级锁和Lock实现的锁区别

目录
  • 一、Lock类层次结构及相关API
    • 1、Lock类层级结构
    • 2、Lock接口相关API
    • 3、关于Condition
  • 二、synchronized VS Lock
    • 1、synchronized实现的锁优缺点
    • 2、Lock实现的锁优缺点
  • 三、手撸一把简单的ReentrantLock
    • 1、ReentrantLock实现简单流程
    • 2、代码示例
    • 3、测试用例

一、Lock类层次结构及相关API 1、Lock类层级结构

ReentrantLock和ReentrantReadWriteLock都是java.util.concurrent并发包下的工具类,ReentrantLock实现了Lock接口,ReentrantReadWriteLock实现了ReadWriteLock接口,而其中的ReadLock和WriteLock又实现了Lock接口。

2、Lock接口相关API

为了区别synchronized和ReentrantLock,我们先了解一下Lock接口相关的API。

结论:
1、lock()最常用。
2、lockInterruptibly()方法一般更昂贵,有的impl可能没有实现lockInterruptibly,只有真的需要响应中断时才使用。

3、关于Condition

Object中的wait()、notify()、notifyAll()只能和synchronized关键字配合使用,可以唤醒一个或全部线程。Condition需要与Lock配合使用,提供多个等待集合,更精确的控制。

备注:如果说Lock代替了同步代码块或同步方法的加解锁逻辑,那么Condition则是代替了Object的等待和唤醒逻辑。



二、synchronized VS Lock 1、synchronized实现的锁优缺点

我们先说说synchronized实现的平台级锁的优点:

  1. 使用简单,语义清晰,在方法上加上synchronized关键字或者使用同步代码块即可。
  2. 由JVM提供,提供了多种优化方案,如锁粗化、锁消除、偏向锁、轻量级锁、重量级锁等,关于这些优化特性请参考:Java面试题之synchronized关键字原理以及锁相关。
  3. 锁的释放由JVM完成,不用人工干预,也降低了死锁的可能性。

再说说它的缺点:
无法实现一些锁的高级功能,如超时锁、中断锁、读写锁、共享锁、公平锁。

2、Lock实现的锁优缺点

Lock实现的锁主要弥补了synchronized的缺点,比如上面提到的锁的高级功能,如超时锁、中断锁、读写锁、共享锁、公平锁这些。

再说一下它的缺点:

  1. 需手动释放锁,新手使用不当可能造成死锁。
  2. 没有synchronized实现的锁那么多优化项。


三、手撸一把简单的ReentrantLock 1、ReentrantLock实现简单流程

先介绍一下一些关键属性,如下:

  • waiters代表锁池,说白了就是抢锁失败线程的等待队列。
  • owner代表成功获取到锁的线程。
  • count用来标记锁的可重入次数。

先描述下加锁流程:

  1. 如果可重入次数为0代表锁还没有被任何线程持有,这时可以通过CAS(0, count + 1)操作进行抢锁。
  2. 如果可重入次数不为0,则判断当前抢锁的线程是不是持有锁的线程,如果是则将可重入次数+1即可。
  3. 如果如上两种条件都不满足,则直接算抢锁失败。
  4. 抢锁失败的线程直接进入等待队列,并阻塞等待。

再描述下解锁流程:

  1. 如果调用解锁方法的线程不是持有锁的线程,则抛出IllegalMonitorStateException,否则第2步。
  2. 将可重入次数-1,如果可重入次数为0则代表解锁成功。
  3. 解锁成功后唤醒队列头部等待的抢锁线程。
2、代码示例
public class NicksReentrantLock implements Lock {

	// 用来标识哪个线程获取到锁
	private Thread owner;

	// 重入次数
	private AtomicInteger counter = new AtomicInteger(0);

	// 等待队列
	private BlockingQueue waiters = new LinkedBlockingQueue<>();

	@Override
	public void lock() {
		if (!tryLock()) {
			waiters.offer(Thread.currentThread());
			// 循环解决伪唤醒问题
			while (true) {
				// 如果队列头部是当前线程说明可以抢锁
				if (Thread.currentThread() == waiters.peek()) {
					// 若抢锁成功则出队列
					if (tryLock()) {
						waiters.poll();
						return;
					}
				}
				// 若当前线程不在队列头部或者抢锁失败则挂起
				LockSupport.park();
			}
		}
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {

	}

	@Override
	public boolean tryLock() {
		int ct = counter.get();
		if (ct == 0) {
			// 重入次数为0说明当前线程可以通过CAS操作获取锁
			if (counter.compareAndSet(0, ct + 1)) {
				owner = Thread.currentThread();
				return true;
			}

			return false;
		}

		// 不为0则判断获取锁的线程是否是当前线程,如果是当前线程,则将可重入次数加1
		if (owner == Thread.currentThread()) {
			counter.set(ct + 1);
			return true;
		}

		return false;
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return false;
	}

	@Override
	public void unlock() {
		// 解锁成功应该唤醒队列头部的线程
		if (tryUnlock()) {
			Optional.ofNullable(waiters.peek()).ifPresent(LockSupport::unpark);
		}
	}

	public boolean tryUnlock() {
		// 如果当前解锁的线程不是获取到锁的线程则抛异常
		if (Thread.currentThread() != owner) {
			throw new IllegalMonitorStateException();
		}

		int ct = counter.get();
		int nextCt = ct - 1;
		counter.set(nextCt);

		if (nextCt == 0) {
			owner = null;
			return true;
		}

		return false;
	}

	@Override
	public Condition newCondition() {
		return null;
	}
}
3、测试用例
public class Test {

	private static int count = 0;

	public static void main(String[] args) {
		NicksReentrantLock lock = new NicksReentrantLock();
		for (int index = 0; index < 10000; index++) {
			new Thread(() -> {
				try {
					lock.lock();
					count++;
				} finally {
					lock.unlock();
				}
			}).start();
		}

		LockSupport.parkNanos(1000 * 1000 * 1000);
		System.out.println("累加后的值为:" + count);
	}
}

备注:控制台输出为: 累加后的值为:10000。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995159.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号