java并发面试题,字节跳动8年老Java面试官经验谈

本文由一位拥有丰富经验的阿里P7级别的Java开发者撰写,分享了在字节跳动面试中遇到的Java并发问题,包括公平锁与非公平锁的区别、Condition的应用、LockSupport的作用、AbstractQueuedSynchronizer(AQS)的内部数据结构、线程安全、线程池的原理与应用等关键知识点。文章还涵盖了线程间的通信方式,如volatile、wait/notify机制、threadLocal等,并探讨了并发编程中的锁类型,如互斥锁、自旋锁、乐观锁、悲观锁,以及并发容器如ConcurrentHashMap的实现。此外,作者还分享了手写死锁和生产者消费者的代码示例,以及线程池的优缺点和使用场景。文章最后提供了全面的Java并发面试题集,帮助读者系统性地学习和准备面试。
摘要由CSDN通过智能技术生成

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

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

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

private volatile int state;

当这个state==0时,表示锁是空闲的,大于零表示锁已经被占用, 它的数值表示当前线程重复占用这个锁的次数。因此,lock()的最简单的实现是:

final void lock() {

// compareAndSetState就是对state进行CAS操作,如果修改成功就占用锁

if (compareAndSetState(0, 1))

setExclusiveOwnerThread(Thread.currentThread());

else

//如果修改不成功,说明别的线程已经使用了这个锁,那么就可能需要等待

acquire(1);

}

下面是acquire() 的实现:

public final void acquire(int arg) {

//tryAcquire() 再次尝试获取锁,

//如果发现锁就是当前线程占用的,则更新state,表示重复占用的次数,

//同时宣布获得所成功,这正是重入的关键所在

if (!tryAcquire(arg) &&

// 如果获取失败,那么就在这里入队等待

acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

//如果在等待过程中 被中断了,那么重新把中断标志位设置上

selfInterrupt();

}

公平锁和非公平锁区别

//非公平锁

final void lock() {

//上来不管三七二十一,直接抢了再说

if (compareAndSetState(0, 1))

setExclusiveOwnerThread(Thread.currentThread());

else

//抢不到,就进队列慢慢等着

acquire(1);

}

//公平锁

final void lock() {

//直接进队列等着

acquire(1);

}

非公平锁如果第一次争抢失败,后面的处理和公平锁是一样的,都是进入等待队列慢慢等。

3.Condition

概述

Condition接口可以理解为重入锁的伴生对象。它提供了在重入锁的基础上,进行等待和通知的机制。可以使用 newCondition()方法生成一个Condition对象。

private final Lock lock = new ReentrantLock();

private final Condition condition = lock.newCondition();

应用场景

在ArrayBlockingQueue阻塞队列中,就维护一个Condition对象

lock = new ReentrantLock(fair);

notEmpty = lock.newCondition();

这个notEmpty 就是一个Condition对象。它用来通知其他线程,ArrayBlockingQueue是不是空着的。当我们需要拿出一个元素时:

public E take() throws InterruptedException {

final ReentrantLock lock = this.lock;

lock.lockInterruptibly();

try {

while (count == 0)

// 如果队列长度为0,那么就在notEmpty condition上等待了,一直等到有元素进来为止

// 注意,await()方法,一定是要先获得condition伴生的那个lock,才能用的哦

notEmpty.await();

//一旦有人通知我队列里有东西了,我就弹出一个返回

return dequeue();

} finally {

lock.unlock();

}

}

当有元素入队时:

public boolean offer(E e) {

checkNotNull(e);

final ReentrantLock lock = this.lock;

//先拿到锁,拿到锁才能操作对应的Condition对象

lock.lock();

try {

if (count == items.length)

return false;

else {

//入队了, 在这个函数里,就会进行notEmpty的通知,通知相关线程,有数据准备好了

enqueue(e);

return true;

}

} finally {

//释放锁了,等着的那个线程,现在可以去弹出一个元素试试了

lock.unlock();

}

}

private void enqueue(E x) {

final Object[] items = this.items;

items[putIndex] = x;

if (++putIndex == items.length)

putIndex = 0;

count++;

//元素已经放好了,通知那个等着拿东西的人吧

notEmpty.signal();

}

在这里插入图片描述

4.LockSupport类

LockSupport可以理解为一个工具类。它的作用很简单,就是挂起和继续执行线程。它的常用的API如下:

public static void park() : 如果没有可用许可,则挂起当前线程

public static void unpark(Thread thread):给thread一个可用的许

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值