JUC之ArrayBlockingQueue与LinkedBlockingQueue

本文详细介绍了Java并发库中的ArrayBlockingQueue和LinkedBlockingQueue两种阻塞队列实现。ArrayBlockingQueue基于数组,利用ReentrantLock和Condition确保并发安全性;而LinkedBlockingQueue使用链表结构,支持两端操作,提供更高的吞吐量。文章深入探讨了两者在add、offer、put、remove、poll和take等操作上的实现细节和线程安全策略。
摘要由CSDN通过智能技术生成

ArrayBlockingQueue

1.基于数组实现,保证并发的安全性是基于 ReetrantLock 和 Condition 实现的。其中有两个重要的成 员变量 putindex 和 takeindex,这两个需要搞懂,putindex 就是指向数组中上一个添加完元素的位置的 下一个地方,比如刚在 index=1 的位置添加完,那么 putindex 就是 2,其中有一点特别注意的就是当 index=数组的长度减一的时候,意味着数组已经到了满了,那么需要将 putindex 置位 0,原因是数 组在被消费的也就是取出操作的时候,是从数组的开始位置取得,所以最开始的位置容易是空的,所 以把要添加的位置置位 0;takeindex 也是一样的,当 takeindex 到了数组的长度减一的时候,也需要 将 takeindex 置为 0。
2.add offer put
add 调用了 offer 方法 add 方法数组满了则抛出异常
offer 方法:用 ReetracLock 加锁,首先判断数组是否满了,数组满了则返回 false,数组不满的话直 接入队,也就是将 putindex 索引处的值置为新要加入的数,如果加入以后发现 putindex++ = 数组的 长度,那么说明后面的全部已经填满了,因此putindex置为0,因为前面的可能出队的过程空出来了, 所以变为 0,最后一步就是执行 notEmpty.signal 去唤醒消费的执行了 take 的线程,只有可能是执行 了 take 的方法的线程,因为执行了其它方法 remove,poll 不会产生线程的挂起操作。
put:首先是 ReetrantLock 加锁,然后判断是否满了,队列满了,则执行 notFull.await()操作挂起,等 待 notFull.signal()唤醒。没满,则直接进行入队,入队和 offer 操作一样,也就是将 putindex 索引 处的值置为新要加入的数,如果加入以后发现 putindex++ = 数组的长度,那么说明后面的全部已经 填满了,因此 putindex 置为 0,因为前面的可能出队的过程空出来了,所以变为 0,最后一步就是执 行 notEmpty()去唤醒消费的执行了 take 的线程
3.remove,poll,take
poll 首先加锁 ReetranLock ,然后判断队列是否为空,不为空,则将 putindex 出的值用副本 copy,然 后置位 null,然后去执行唤醒 notFull()操作,也就是唤醒调用了 put 操作的线程,唤醒操作并不一定总 是发生。
take 操作,先加锁,然后如果队列空则 notEmpty.await()方法,不为空,则执行和 poll 一样的出队操 作:则将 putindex 出的值用副本 copy,然后置位 null,然后去执行唤醒 notFull()操作

LinkedBlockingQueue(JDK1.6)

1.基于链表实现,有 takelock 和 putlock,也就是说可以同时在首尾两端进行操作,因此吞吐量比 ArrayBlockingQueue 大,同时由于首尾两端都可以进行操作,所以当在进行添加的操作的过程可以 一直去添加,直到没有被阻塞的添加线程为止,然后才去执行消费的线程。
1.add,offer,put
add 调用 offer,满了抛出异常
offer 方法 putlock 锁,然后不满则加入,同时获取一个 c 值,c 值代表本次队列增加前的队列的数目 (一开始长度 2,增加 1,现在长度是 3,那么 c 就是 2),然后判断如果不满则继续去唤醒 notFull.signl, 去唤醒添加线程去添加(添加过程是直接 last 节点指向下一个,简单的节点后增加一个节点,然后 last 指向最后一个节点),上述过程结束,然后去判断 c==0(c 代表了之前的队列长度,如果添加之前队 列长度是 0 那么说明可能有挂起的消费线程,需要从队列取元素,但队列长度为 0 没有元素;判断 c>0 没有意义,因为添加之前队列不为空,说明不存在挂起的消费线程,挂起的原因是因为队列为空, 所以不存在因此源码是判断 c==0) ,c 如果等于 0 那么去唤醒阻塞的 notEmpty 上的条件等待线程。 put 操作就是满了则挂起,不满则执行,同时添加完一个后,发现没满继续去唤醒挂起的添加线程 2.poll take
反之,一样的逻辑
poll 则获取 takelcok 然后不为空则出队一个元素,也就是链表的删除头结点操作,通过是如果队列 不为空,那么继续去唤醒被挂起的消费线程(消费线程就是执行了队列的 take 操作的线程),直到 没有消费线程或者队列为空,结束,然后如果 c(也是队列消费一个头节点的元素后,没消费之前的 长度,没发生删除的时候队列的长度),如果 c 的长度已经是队列的长度,则去唤醒被挂起的执行了 put 方法的线程,然后释放 takelock 锁
take 方法一样的道理,为空则挂起,不为空一直消费,唤起消费线程一直消费,直到条件不满足,那 么去尝试判断 c 的值,c 是队列长度减一,那么去唤醒执行了 put 方法的被挂起的线程。

https://blog.csdn.net/javazejian/article/details/77410889

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值