【大厂Java并发编程面试题解】显式锁(Explicit Locks),2024年最新面试必备的资料有哪些

  • 通过 L 可以知道是否成功获得锁,S 不可以

  • L 可以提高多个线程进行读写操作的效率

3 Lock的特性

========================================================================

  • 可定时锁等待

  • 可轮询锁等待

  • 可中断锁等待

  • 公平性

  • 实现非块结构的加锁

  • 绑定多个Condition。通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal();

3.1 轮询锁和定时锁


内置锁的死锁问题只能通过重启解决,可定时、可轮询锁提供了另一种选择:

通过tryLock解决

public class DeadlockAvoidance {

private static Random rnd = new Random();

public boolean transferMoney(Account fromAcct,

Account toAcct,

DollarAmount amount,

long timeout,

TimeUnit unit)

throws InsufficientFundsException, InterruptedException {

long fixedDelay = getFixedDelayComponentNanos(timeout, unit);

long randMod = getRandomDelayModulusNanos(timeout, unit);

long stopTime = System.nanoTime() + unit.toNanos(timeout); //定时,轮询

while (true) {

if (fromAcct.lock.tryLock()) {

try {

if (toAcct.lock.tryLock()) {

try {

if (fromAcct.getBalance().compareTo(amount) < 0)

throw new InsufficientFundsException();

else {

fromAcct.debit(amount);

toAcct.credit(amount);

return true;

}

} finally {

toAcct.lock.unlock();

}

}

} finally {

fromAcct.lock.unlock();

}

}

if (System.nanoTime() < stopTime)

return false;

NANOSECONDS.sleep(fixedDelay + rnd.nextLong() % randMod);

}

}

private static final int DELAY_FIXED = 1;

private static final int DELAY_RANDOM = 2;

static long getFixedDelayComponentNanos(long timeout, TimeUnit unit) {

return DELAY_FIXED;

}

static long getRandomDelayModulusNanos(long timeout, TimeUnit unit) {

return DELAY_RANDOM;

}

static class DollarAmount implements Comparable {

public int compareTo(DollarAmount other) {

return 0;

}

DollarAmount(int dollars) {

}

}

class Account {

public Lock lock;

void debit(DollarAmount d) {

}

void credit(DollarAmount d) {

}

DollarAmount getBalance() {

return null;

}

}

class InsufficientFundsException extends Exception {

}

}

3.2 带有时间限制的锁


3.3 可中断的锁


3.4关于Condition


最典型的就是阻塞的有界队列的实现。

public class BoundedBuffer {

private static final Logger logger = LoggerFactory.getLogger(BoundedBuffer.class);

final Lock lock = new ReentrantLock();

final Condition notFull = lock.newCondition();

final Condition notEmpty = lock.newCondition();

final Object[] items = new Object[2]; // 阻塞队列

int putptr, takeptr, count;

private void log(String info) {

logger.info(Thread.currentThread().getName() + " - " + info);

}

public void put(Object x) throws InterruptedException {

log(x + “,执行put”);

lock.lock();

log(x + “,put lock.lock()”);

try {

while (count == items.length) { // 如果队列满了,notFull就一直等待

log(x + “,put notFull.await() 队列满了”);

notFull.await(); // 调用await的意思取反,及not notFull -> Full

}

items[putptr] = x; // 终于可以插入队列

if (++putptr == items.length) {

putptr = 0; // 如果下标到达数组边界,循环下标置为0

}

++count;

log(x + “,put成功 notEmpty.signal() 周知队列不为空了”);

notEmpty.signal(); // 唤醒notEmpty

} finally {

log(x + “,put lock.unlock()”);

lock.unlock();

}

}

public Object take() throws InterruptedException {

log(“执行take”);

lock.lock();

Object x = null;

log(“take lock.lock()”);

try {

while (count == 0) {

log(“take notEmpty.await() 队列为空等等”);

notEmpty.await();

}

x = items[takeptr];

if (++takeptr == items.length) {

takeptr = 0;

}

–count;

log(x + “,take成功 notFull.signal() 周知队列有剩余空间了”);

notFull.signal();

return x;

} finally {

lock.unlock();

log(x + “,take lock.unlock()”);

}

}

public static void main(String[] args) throws InterruptedException {

final BoundedBuffer bb = new BoundedBuffer();

ExecutorService executor = Executors.newFixedThreadPool(10);

for (char i = ‘A’; i < ‘F’; i++) {

final char t = i;

executor.execute(() -> {

try {

bb.put(t);

} catch (InterruptedException e) {

e.printStackTrace();

}

});

}

List res = new LinkedList<>();

for (char i = ‘A’; i < ‘F’; i++) {

executor.execute(() -> {

try {

char c = (char) bb.take();

res.add©;

} catch (InterruptedException e) {

e.printStackTrace();

}

});

}

try {

executor.awaitTermination(2, TimeUnit.SECONDS);

} catch (InterruptedException ie) {

ie.printStackTrace();

}

logger.info(res.toString());

executor.shutdownNow();

}

}

4 性能考虑因素

=======================================================================

Java5的时候J.U.C的ReentrantLock锁竞争性能非常好,到了Java6使用了改进后的算法来管理内置锁,所以现在差不太多了,只好一点点

竞争性能的影响可伸缩性的关键要素:如果有越多的资源被耗费在锁的管理和线程调度上,那么应用程序得到的资源就越少,锁的实现方式越好,将需要越少的系统调用和上下文切换。

5 公平性

====================================================================

ReentrantLock默认创建非公平的锁,非公平指被阻塞挂起的线程(LockSupport.park)都在AQS的CLH队列中排队等待自己被唤醒。他们是按照发出的请求顺序来排队的,但一旦有一个唤醒的就会和新来的线程竞争锁,新来的可能会“插队”。若新来的成功获取锁,那么它将跳过所有等待线程而开始执行,这意味着本该被唤醒的线程失败了,对不起您回到队列的尾部继续等。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

难道这样就够了吗?不,远远不够!

提前多熟悉阿里往年的面试题肯定是对面试有很大的帮助的,但是作为技术性职业,手里有实打实的技术才是你面对面试官最有用的利器,这是从内在散发出来的自信。

备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。

今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

阿里一面就落马,恶补完这份“阿里面试宝典”后,上岸蚂蚁金服

image.png

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

备战阿里时我花的最多的时间就是在学习技术上,占了我所有学习计划中的百分之70,这是一些我学习期间觉得还是很不错的一些学习笔记

我为什么要写这篇文章呢,其实我觉得学习是不能停下脚步的,在网络上和大家一起分享,一起讨论,不单单可以遇到更多一样的人,还可以扩大自己的眼界,学习到更多的技术,我还会在csdn、博客、掘金等网站上分享技术,这也是一种学习的方法。

今天就分享到这里了,谢谢大家的关注,以后会分享更多的干货给大家!

[外链图片转存中…(img-ZZFaaorB-1712958143184)]

[外链图片转存中…(img-pNCWLENs-1712958143185)]

[外链图片转存中…(img-4eLY3oR1-1712958143185)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-EjMrZ4YQ-1712958143185)]

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 什么是Git?它有什么优点? Git是一款版本控制系统,它可以记录代码的历史变化,便于多人协作开发和管理代码。它的优点包括: - 分布式管理:每个开发者都可以拥有一份完整的代码仓库,不需要依赖中央服务器。 - 强大的分支和合并功能:可以轻松地创建和合并分支,便于团队协作和版本管理。 - 快速轻便:Git采用了一些高效的算法和数据结构,使得它的速度非常快。 - 安全性高:Git使用SHA-1算法来保证代码的完整性和安全性。 2. Git的三个区域分别是什么? Git的三个区域分别是工作区、暂存区和版本库。 - 工作区:保存了实际的文件,也就是我们编辑的文件。 - 暂存区:保存了即将提交到版本库的文件,也就是我们通过`git add`命令添加的文件。 - 版本库:保存了所有的提交历史和代码版本,也就是我们通过`git commit`命令提交到Git的代码仓库。 3. 如何创建一个新的分支并切换到这个分支? 可以使用`git branch`命令创建新分支,然后使用`git checkout`命令切换到新分支: ``` $ git branch new_branch # 创建新分支 $ git checkout new_branch # 切换到新分支 ``` 也可以使用`git checkout`命令的`-b`选项,一步完成创建和切换: ``` $ git checkout -b new_branch # 创建新分支并切换到新分支 ``` 4. 如何合并两个分支? 可以使用`git merge`命令合并两个分支: ``` $ git checkout master # 切换到要合并的分支(通常是主分支) $ git merge feature_branch # 合并另一个分支 ``` 在合并过程中,Git会自动检测两个分支的差异,并尝试自动合并代码。如果合并过程中发生冲突,需要手动决冲突,然后再次执行`git merge`命令。 5. 如何撤销上一次提交? 可以使用`git revert`命令撤销上一次提交: ``` $ git revert HEAD # 撤销上一次提交 ``` 这会创建一个新的提交,用于撤销上一次提交的变更。如果需要撤销多个提交,可以使用`git revert`命令的`-n`选项,指定要撤销的提交数量。 6. 如何回退到某个提交? 可以使用`git reset`命令回退到某个提交: ``` $ git reset --hard commit_id # 回退到指定的提交 ``` 这会将当前分支回退到指定的提交,并重写工作区和暂存区的内容。这会丢失当前提交之后的所有提交记录,谨慎使用。 7. 如何查看提交历史? 可以使用`git log`命令查看提交历史: ``` $ git log # 查看提交历史 ``` 这会列出所有提交的记录,包括提交的哈希值、作者、时间、提交消息等信息。可以使用`--pretty`选项指定输出格式。 8. 如何查看文件的差异? 可以使用`git diff`命令查看文件的差异: ``` $ git diff file_path # 查看工作区与当前版本库的差异 $ git diff commit_a..commit_b file_path # 查看两个提交之间的差异 ``` 这会输出文件的变更内容,包括添加、修改、删除等操作。如果需要查看某个文件的历史变更记录,可以使用`git log`命令的`--follow`选项。 9. 如何从远程仓库拉取代码? 可以使用`git pull`命令从远程仓库拉取代码: ``` $ git pull origin master # 从远程仓库的主分支拉取代码 ``` 这会将远程仓库的代码拉取到本地,并自动合并到当前分支。如果需要从其他分支拉取代码,可以修改`origin master`为相应的分支名称。 10. 如何推送代码到远程仓库? 可以使用`git push`命令将代码推送到远程仓库: ``` $ git push origin master # 将代码推送到远程仓库的主分支 ``` 这会将当前分支的代码推送到远程仓库,并更新远程仓库的代码。如果需要推送到其他分支,可以修改`origin master`为相应的分支名称。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值