15分钟面试被5连CALL,你扛得住么?

2024-06-13  本文已影响0人  威哥爱编程

最近一个朋友跳槽找工作,跟V 哥说被15分钟内一个问题5连 CALL,还好是自己比较熟悉的技术点,面试官最后跟他说,面了几十个人,你是第一个回答比较满意的,我好奇都是什么问题,原来是关于锁的问题连环问,整理出来给需要的兄弟们参考。

第1问:Java 项目中为什么需要锁?

在Java项目中,锁(Locks)是并发编程中非常重要的一个概念,主要用于控制对共享资源的访问以保证数据的一致性和线程安全。以下是Java项目中需要锁的一些原因:

举个例子,618马上到了,在0点这一刻,如果有几十万甚至上百万的人同时去查看某个商品的详情,这时候会触发商品的查询,如果我们不做控制,全部走到数据库去,那是有可能直接将数据库打垮的。

在这种情况下,数据库成为了一个共享资源,所有用户都试图同时访问它。如果不进行任何控制,数据库可能会因为并发请求过多而崩溃,导致服务不可用。

使用锁(例如,通过缓存机制实现的分布式锁)可以限制同时访问数据库的线程数量。一个线程获取锁后,可以执行数据库查询,其他线程则需要等待这个线程完成查询并释放锁后才能继续。

此外,还可以通过缓存技术来优化性能,将商品详情缓存起来,这样大部分请求可以直接从缓存中获取数据,减少对数据库的直接访问。

在Java中,锁的实现可以通过多种方式,包括但不限于synchronized关键字、ReentrantLock类、ReadWriteLock接口等。正确地使用锁对于构建高效、可靠的并发应用程序至关重要。

第2问:Java 项目中为什么需要锁?

分布式锁是分布式系统中用于确保跨多个节点或服务的多个进程能够安全地访问共享资源的一种同步机制。以下是为什么需要分布式锁的一些原因:

实现分布式锁的技术包括基于数据库的锁、基于Redis的RedLock算法、基于ZooKeeper的分布式锁等。正确地实现和使用分布式锁对于构建可靠、可扩展的分布式系统至关重要。

第3问:实现分布式锁的方式有哪些?

实现分布式锁的方式主要有以下几种:

每种实现方式都有其特点和适用场景,选择合适的实现方式需要根据具体的业务需求和系统架构来决定。

第4问:分布式锁如何实现?请详细举例和说明?

分布式锁的实现通常需要满足以下条件:互斥性、安全性、性能、死锁预防机制、高可用性和容错性。

以下是几种常见的分布式锁实现方式,每种方式都通过具体的例子来说明:

1. 基于数据库的唯一索引实现分布式锁

例子:
假设有一个电商系统,需要对库存操作进行加锁以防止超卖。

CREATE TABLE lock_table (
  id INT AUTO_INCREMENT PRIMARY KEY,
  lock_key VARCHAR(255) NOT NULL,
  owner_id INT NOT NULL,
  UNIQUE KEY unique_lock_key (lock_key)
);
INSERT INTO lock_table (lock_key, owner_id) VALUES ('inventory_123', 1);

如果插入成功,则认为获取了锁;如果因为唯一性冲突而失败,则需要等待或重试。

DELETE FROM lock_table WHERE lock_key = 'inventory_123' AND owner_id = 1;

2. 基于Redis的SETNX命令实现分布式锁

例子:
使用Redis缓存来实现一个分布式锁,以控制对某个资源的并发访问。

redis-cli SETNX lock_key unique_value

SETNX命令会原子性地检查lock_key是否存在,如果不存在,则设置其值为unique_value并返回1,表示成功获取锁;如果存在,则返回0,表示锁被其他进程持有。

redis-cli EXPIRE lock_key 10
redis-cli EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock_key unique_value

3. 基于Zookeeper的临时顺序节点实现分布式锁

例子:
使用Zookeeper来实现一个分布式锁,适用于需要高可用性和一致性的系统。

4. 基于Redisson的分布式锁

例子:
使用Redisson框架简化Redis分布式锁的实现。

Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
RLock lock = redisson.getLock("lock_object");
    try {
      lock.lock();
      // 执行业务逻辑
    } finally {
      lock.unlock();
    }

Redisson内部使用了Redis的原子命令和Lua脚本来确保锁的安全性和性能。

每种实现方式都有其适用场景和潜在的问题,例如基于数据库的锁可能受到数据库性能的限制,基于Redis的锁需要处理网络分区和超时问题,基于Zookeeper的锁可能涉及到复杂的Watcher管理。在实际应用中,需要根据具体需求和环境来选择最合适的实现方式。

第5问:分布式锁如何选型?

分布式锁的选型是一个复杂的问题,需要考虑多个因素,包括但不限于性能、可靠性、可扩展性、维护成本以及特定场景的需求。以下是一些常见的分布式锁实现方案及其特点,以及如何根据CAP模型进行选型:

1. 基于Redis的分布式锁:

2. 基于ZooKeeper的分布式锁:

3. 基于数据库的分布式锁:

在选择分布式锁时,需要根据CAP模型来权衡:

例如,在对一致性要求较高的场景下,如电商、银行支付等,可能更倾向于选择ZooKeeper或数据库分布式锁。而在对可用性要求较高的场景下,可能会选择Redis分布式锁。此外,如果系统可以容忍少量数据丢失,出于维护成本等因素考虑,可能会优先选择基于Redis的AP模型的分布式锁。

最终的选型需要综合考虑业务场景的具体需求和上述因素,以找到最适合的分布式锁方案。

上一篇下一篇

猜你喜欢

热点阅读