文章目录
BlockingQueue是JUC包下提供的一个阻塞队列 接口;

队列操作
其中:BlockingQueue 不接受 null 元素。试图 add 、 put 或 offer ⼀个 null 元素时,某些实现会抛出 NullPointerException 。

ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:由链表组成的有界阻塞队列。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列(默认升序排序)。
DelayQueue:支持延时获取元素的无界阻塞队列。
队列使用PriorityQueue来实现。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:由链表组成的无界阻塞队列。
其多了tryTransfer()方法和transfer()方法。
ArrayBlockingQueue是由数组结构组成的有界阻塞队列。通过ReentrantLock保证线程安全、并实现 Producer-Consumer模式。

从构造函数可知,默认采用非公平锁;
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
// 底层使用对象数组保存元素
this.items = new Object[capacity];
// 初始化需要加锁使用的ReentrantLock实例,默认采用非公平锁
lock = new ReentrantLock(fair);
/**
* 判断队列是 空 or 满
* notEmpty⽤于执⾏take时进⾏await()等待操作,put时进⾏signal()唤醒操作
* notFull⽤于执⾏take时进⾏signal()唤醒操作,put时进⾏await()等待操作
*/
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
方法释义:
- 构造函数的入参capacity指定了底层存储元素数组⻓度的⼤⼩;
- 初始化需要加锁使⽤的ReentrantLock实例,默认采⽤的是⾮公平锁;
- 基于Lock的Condition判断队列是 空 or 满
- notEmpty⽤于执⾏take时进⾏await()等待操作,put时进⾏signal()唤醒操作;
- notFull⽤于执⾏take时进⾏signal()唤醒操作,put时进⾏await()等待操作;
public void put(E e) throws InterruptedException {
// 入参不能为空
checkNotNull(e);
final ReentrantLock lock = this.lock;
// 加可中断锁
lock.lockInterruptibly();
try {
while (count == items.length)
// 队列满了,则阻塞等待signal唤醒,同时释放次有的锁。
notFull.await();
// 入队操作
enqueue(e);
} finally {
lock.unlock();
}
}
private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x;
// 如果数据已经插入到数组末尾,则重置putIndex为0,从0开始继续插入。
if (++putIndex == items.length)
putIndex = 0;
count++;
// 通知take线程解除阻塞
notEmpty.signal();
}
方法释义:
- ⾸先尝试获得可中断锁,即:lock.lockInterruptibly(),当执⾏interrupt操作时,该锁可以被中断。
- 如果数组中元素的个数(count)等于数组的⻓度了,说明队列已经满了,在该线程上执⾏等待操作:
notFull.await();,等待signal唤醒。- 如果队列没有满,则调⽤enqueue(e)⽅法执⾏⼊列操作;
- ⼊列操作⾸先会将待插⼊值x放⼊数组下标为putIndex的位置上,然后再将putIndex加1,来指向下⼀次插⼊的下标位置。
- 如果加1后的putIndex等于了数组的⻓度,那么说明已经越界了(因为putIndex是从0开始的);则
做循环式插⼊,重置putIndex为0,从0开始继续插入。- 最后,执⾏count++来计算元素总个数;并调⽤notEmpty.signal()⽅法来解除阻塞;
- 当队列为空的时候,执⾏take⽅法会被notEmpty.await()阻塞;
- 此处就是通知take线程解除阻塞。
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
// 如果队列为空,则线程阻塞 等待signal唤醒,释放持有的锁
notEmpty.await();
// 执行出队操作
return dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
final Object[] items = this.items;
@SuppressWarnings("unchecked")
// 获取takeIndex下标的元素
E x = (E) items[takeIndex];
// 将takeIndex下标下的袁术置为null,便于后面GC回收
items[takeIndex] = null;
// 如果出队操作的到了数组末尾,则重置takeIndex,从0开始继续取出
if (++takeIndex == items.length)
takeIndex = 0;
count--;
// 默认itrs为null,不会走进if代码段。
if (itrs != null)
itrs.elementDequeued();
// 通知put线程解除阻塞
notFull.signal();
return x;
}
方法释义:
take⽅法和put⽅法类似,区别是出队的指针是takeIndex;
⾸先尝试获得可中断锁,即:lock.lockInterruptibly(),当执⾏interrupt操作时,该锁可以被中断。
如果队列中为空;
执⾏notEmpty.await()将线程阻塞 等待signal唤醒,释放持有的锁。
- 当调⽤put⽅法向队列中放⼊元素之后 ,会调⽤notEmpty.signal⽅法对等待的线程执⾏唤醒操作;
如果出队操作的到了数组末尾,则重置takeIndex,从0开始继续取出;
出队执⾏完毕后,调⽤
notFull.signal⽅法来唤醒在notFull上⾯await的线程。 通知put线程解除阻塞。
LinkedBlockingQueue是由链表结构组成的有界阻塞队列。通过ReentrantLock保证线程安全、并实现 Producer-Consumer模式。
如果不指定容量,则默认LinkedBlockingQueue是无界阻塞队列(capacity = Integer.MAX_VALUE)

构造函数中会创建⼀个空的节点,作为整个链表的头节点。

private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
last = last.next = node;
}
整个put()流程和ArrayBlockingQueue基本一致,对于链表容量的统计会额外采用一个AtomiceInteger类型的变量count维护。
c == 0的判断,这里的c是入队操作之前的数量。/** Current number of elements */
private final AtomicInteger count = new AtomicInteger();
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
这里有个比较有意思的点:
if (c + 1 < capacity)
notFull.signal();

private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
// assert head.item == null;
Node<E> h = head;
Node<E> first = h.next;
h.next = h; // help GC
head = first;
E x = first.item;
first.item = null;
return x;
}
整个take()流程和ArrayBlockingQueue基本一致,稍微看一下即可。
c == capacity的判断,这里的c是出队操作之前的数量。和LinkedBlockingQueue的put()操作一样:
if (c > 1)
notEmpty.signal();
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。
我正在查看Ruby日志记录库Logging.logger方法并从sourceatgithub提出问题与这段代码有关:logger=::Logging::Logger.new(name)logger.add_appendersappenderlogger.additive=falseclass我知道类 最佳答案 这实际上删除了方法(当它实际被执行时)。这是确保close不会被调用两次的保障措施。看起来好像有嵌套的“class 关于Ruby元编程问题,我们在StackOverflow上找到一
在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g
使用Paperclip,我想从这样的URL抓取图像:require'open-uri'user.photo=open(url)问题是我最后得到一个像“open-uri20110915-4852-1o7k5uw”这样的文件名。有什么方法可以更改user.photo上的文件名?作为一个额外的变化,Paperclip将我的文件存储在S3上,所以如果我可以在初始分配中设置我想要的文件名就更好了,这样图像就会上传到正确的S3key。像这样:user.photo=open(url),:filename=>URI.parse(url).path 最佳答案
我正在开发一个xcode自动构建系统。在执行一些预构建验证时,我想检查指定的证书文件是否已被撤销。我了解securityverify-cert验证其他证书属性但不验证吊销。我如何检查撤销?我正在用Ruby编写构建系统,但我对任何语言的想法都持开放态度。我阅读了这个答案(Openssl-Howtocheckifacertificateisrevokedornot),但指向底部的链接(DoesOpenSSLautomaticallyhandleCRLs(CertificateRevocationLists)now?)进入的Material对我的目的来说有点过于复杂(用户上传已撤销的证书是一
关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby有很大不同。由于我与ruby之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?