阻塞队列的java代码 java等待队列和阻塞队列

java 中 阻塞队列 非阻塞队列 和普通队列的区别是什么

阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列.

专业成都网站建设公司,做排名好的好网站,排在同行前面,为您带来客户和效益!创新互联建站为您提供成都网站建设,五站合一网站设计制作,服务好的网站设计公司,成都网站制作、做网站、外贸营销网站建设负责任的成都网站制作公司!

1.ArrayDeque, (数组双端队列)

2.PriorityQueue, (优先级队列)

3.ConcurrentLinkedQueue, (基于链表的并发队列)

4.DelayQueue, (延期阻塞队列)(阻塞队列实现了BlockingQueue接口)

5.ArrayBlockingQueue, (基于数组的并发阻塞队列)

6.LinkedBlockingQueue, (基于链表的FIFO阻塞队列)

7.LinkedBlockingDeque, (基于链表的FIFO双端阻塞队列)

8.PriorityBlockingQueue, (带优先级的无界阻塞队列)

9.SynchronousQueue (并发同步阻塞队列)

阻塞队列和生产者-消费者模式

阻塞队列(Blocking queue)提供了可阻塞的put和take方法,它们与可定时的offer和poll是等价的。如果Queue已经满了,put方法会被阻塞直到有空间可用;如果Queue是空的,那么take方法会被阻塞,直到有元素可用。Queue的长度可以有限,也可以无限;无限的Queue永远不会充满,所以它的put方法永远不会阻塞。

阻塞队列支持生产者-消费者设计模式。一个生产者-消费者设计分离了“生产产品”和“消费产品”。该模式不会发现一个工作便立即处理,而是把工作置于一个任务(“to do”)清单中,以备后期处理。生产者-消费者模式简化了开发,因为它解除了生产者和消费者之间相互依赖的代码。生产者和消费者以不同的或者变化的速度生产和消费数据,生产者-消费者模式将这些活动解耦,因而简化了工作负荷的管理。

生产者-消费者设计是围绕阻塞队列展开的,生产者把数据放入队列,并使数据可用,当消费者为适当的行为做准备时会从队列中获取数据。生产者不需要知道消费者的省份或者数量,甚至根本没有消费者—它们只负责把数据放入队列。类似地,消费者也不需要知道生产者是谁,以及是谁给它们安排的工作。BlockingQueue可以使用任意数量的生产者和消费者,从而简化了生产者-消费者设计的实现。最常见的生产者-消费者设计是将线程池与工作队列相结合。

阻塞队列简化了消费者的编码,因为take会保持阻塞直到可用数据出现。如果生产者不能足够快地产生工作,让消费者忙碌起来,那么消费者只能一直等待,直到有工作可做。同时,put方法的阻塞特性也大大地简化了生产者的编码;如果使用一个有界队列,那么当队列充满的时候,生产者就会阻塞,暂不能生成更多的工作,从而给消费者时间来赶进进度。

有界队列是强大的资源管理工具,用来建立可靠的应用程序:它们遏制那些可以产生过多工作量、具有威胁的活动,从而让你的程序在面对超负荷工作时更加健壮。

虽然生产者-消费者模式可以把生产者和消费者的代码相互解耦合,但是它们的行为还是间接地通过共享队列耦合在一起了

类库中包含一些BlockingQueue的实现,其中LinkedBlockingQueue和ArrayBlockingQueue是FIFO队列,与 LinkedList和ArrayList相似,但是却拥有比同步List更好的并发性能。PriorityBlockingQueue是一个按优先级顺序排序的队列,当你不希望按照FIFO的属性处理元素时,这个PriorityBolckingQueue是非常有用的。正如其他排序的容器一样,PriorityBlockingQueue可以比较元素本身的自然顺序(如果它们实现了Comparable),也可以使用一个 Comparator进行排序。

最后一个BlockingQueue的实现是SynchronousQueue,它根本上不是一个真正的队列,因为它不会为队列元素维护任何存储空间。不过,它维护一个排队的线程清单,这些线程等待把元素加入(enqueue)队列或者移出(dequeue)队列。因为SynchronousQueue没有存储能力,所以除非另一个线程已经准备好参与移交工作,否则put和take会一直阻止。SynchronousQueue这类队列只有在消费者充足的时候比较合适,它们总能为下一个任务作好准备。

非阻塞算法

基于锁的算法会带来一些活跃度失败的风险。如果线程在持有锁的时候因为阻塞I/O,页面错误,或其他原因发生延迟,很可能所有的线程都不能前进了。

一个线程的失败或挂起不应该影响其他线程的失败或挂起,这样的算法成为非阻塞(nonblocking)算法;如果算法的每一个步骤中都有一些线程能够继续执行,那么这样的算法称为锁自由(lock-free)算法。在线程间使用CAS进行协调,这样的算法如果能构建正确的话,它既是非阻塞的,又是锁自由的。非竞争的CAS总是能够成功,如果多个线程以一个CAS竞争,总会有一个胜出并前进。非阻塞算法堆死锁和优先级倒置有“免疫性”(但它们可能会出现饥饿和活锁,因为它们允许重进入)。

非阻塞算法通过使用低层次的并发原语,比如比较交换,取代了锁。原子变量类向用户提供了这些底层级原语,也能够当做“更佳的volatile变量”使用,同时提供了整数类和对象引用的原子化更新操作

「每天一道面试题」Java中的阻塞队列有哪些

Java里的阻塞队列有以下几种:

ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。

LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。

PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。

DelayQueue:一个使用优先级队列实现的无界阻塞队列。

SynchronousQueue:一个不存储元素的阻塞队列。

LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

java阻塞队列 线程同步合作

Queue接口与List Set同一级别 都是继承了Collection接口 LinkedList实现了Queue接口 Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时 就完全只能访问Queue接口所定义的方法了 而不能直接访问 LinkedList的非Queue的方法) 以使得只有恰当的方法才可以使用 BlockingQueue 继承了Queue接口

队列是一种数据结构.它有两个基本操作 在队列尾部加人一个元素 和从队列头部移除一个元素就是说 队列以一种先进先出的方式管理数据 如果你试图向一个已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索 将导致线程阻塞.在多线程进行合作时 阻塞队列是很有用的工具 工作者线程可以定期地把中间结果存到阻塞队列中而其他工作者线线程把中间结果取出并在将来修改它们 队列会自动平衡负载 如果第一个线程集运行得比第二个慢 则第二个线程集在等待结果时就会阻塞 如果第一个线程集运行得快 那么它将等待第二个线程集赶上来 下表显示了jdk 中的阻塞队列的操作

add        增加一个元索                     如果队列已满 则抛出一个IIIegaISlabEepeplian异常

remove   移除并返回队列头部的元素    如果队列为空 则抛出一个NoSuchElementException异常

element  返回队列头部的元素             如果队列为空 则抛出一个NoSuchElementException异常

offer       添加一个元素并返回true       如果队列已满 则返回false

poll         移除并返问队列头部的元素    如果队列为空 则返回null

peek       返回队列头部的元素             如果队列为空 则返回null

put         添加一个元素                      如果队列满 则阻塞

take        移除并返回队列头部的元素     如果队列为空 则阻塞

remove element offer poll peek 其实是属于Queue接口

阻塞队列的操作可以根据它们的响应方式分为以下三类 aad removee和element操作在你试图为一个已满的队列增加元素或从空队列取得元素时抛出异常 当然 在多线程程序中 队列在任何时间都可能变成满的或空的 所以你可能想使用offer poll peek方法 这些方法在无法完成任务时只是给出一个出错示而不会抛出异常

注意 poll和peek方法出错进返回null 因此 向队列中插入null值是不合法的

还有带超时的offer和poll方法变种 例如 下面的调用

boolean success = q offer(x TimeUnit MILLISECONDS);

尝试在 毫秒内向队列尾部插入一个元素 如果成功 立即返回true 否则 当到达超时进 返回false 同样地 调用

Object head = q poll( TimeUnit MILLISECONDS);

如果在 毫秒内成功地移除了队列头元素 则立即返回头元素 否则在到达超时时 返回null

最后 我们有阻塞操作put和take put方法在队列满时阻塞 take方法在队列空时阻塞

ncurrent包提供了阻塞队列的 个变种 默认情况下 LinkedBlockingQueue的容量是没有上限的(说的不准确 在不指定时容量为Integer MAX_VALUE 不要然的话在put时怎么会受阻呢) 但是也可以选择指定其最大容量 它是基于链表的队列 此队列按 FIFO(先进先出)排序元素

ArrayBlockingQueue在构造时需要指定容量 并可以选择是否需要公平性 如果公平参数被设置true 等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来达到这种公平性的 即等待时间最长的线程会先操作) 通常 公平性会使你在性能上付出代价 只有在的确非常需要的时候再使用它 它是基于数组的阻塞循环队列 此队列按 FIFO(先进先出)原则对元素进行排序

PriorityBlockingQueue是一个带优先级的队列 而不是先进先出队列 元素按优先级顺序被移除 该队列也没有上限(看了一下源码 PriorityBlockingQueue是对PriorityQueue的再次包装 是基于堆数据结构的 而PriorityQueue是没有容量限制的 与ArrayList一样 所以在优先阻塞队列上put时是不会受阻的 虽然此队列逻辑上是无界的 但是由于资源被耗尽 所以试图执行添加操作可能会导致 OutOfMemoryError) 但是如果队列为空 那么取元素的操作take就会阻塞 所以它的检索操作take是受阻的 另外 往入该队列中的元素要具有比较能力

最后 DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列 只有在延迟期满时才能从中提取元素 该队列的头部是延迟期满后保存时间最长的 Delayed 元素 如果延迟都还没有期满 则队列没有头部 并且poll将返回null 当一个元素的 getDelay(TimeUnit NANOSECONDS) 方法返回一个小于或等于零的值时 则出现期满 poll就以移除这个元素了 此队列不允许使用 null 元素 下面是延迟接口

Java代码

public interface Delayed extends ComparableDelayed {

long getDelay(TimeUnit unit);

}

public interface Delayed extends ComparableDelayed {

long getDelay(TimeUnit unit);

}

放入DelayQueue的元素还将要实现pareTo方法 DelayQueue使用这个来为元素排序

下面的实例展示了如何使用阻塞队列来控制线程集 程序在一个目录及它的所有子目录下搜索所有文件 打印出包含指定关键字的文件列表 从下面实例可以看出 使用阻塞队列两个显著的好处就是 多线程操作共同的队列时不需要额外的同步 另外就是队列会自动平衡负载 即那边(生产与消费两边)处理快了就会被阻塞掉 从而减少两边的处理速度差距 下面是具体实现

Java代码

public class BlockingQueueTest {

public static void main(String[] args) {

Scanner in = new Scanner(System in);

System out print( Enter base directory (e g /usr/local/jdk /src): );

String directory = in nextLine();

System out print( Enter keyword (e g volatile): );

String keyword = in nextLine();

final int FILE_QUEUE_SIZE = ;// 阻塞队列大小

final int SEARCH_THREADS = ;// 关键字搜索线程个数

// 基于ArrayBlockingQueue的阻塞队列

BlockingQueueFile queue = new ArrayBlockingQueueFile(

FILE_QUEUE_SIZE);

//只启动一个线程来搜索目录

FileEnumerationTask enumerator = new FileEnumerationTask(queue

new File(directory));

new Thread(enumerator) start();

//启动 个线程用来在文件中搜索指定的关键字

for (int i = ; i = SEARCH_THREADS; i++)

new Thread(new SearchTask(queue keyword)) start();

}

}

class FileEnumerationTask implements Runnable {

//哑元文件对象 放在阻塞队列最后 用来标示文件已被遍历完

public static File DUMMY = new File( );

private BlockingQueueFile queue;

private File startingDirectory;

public FileEnumerationTask(BlockingQueueFile queue File startingDirectory) {

this queue = queue;

this startingDirectory = startingDirectory;

}

public void run() {

try {

enumerate(startingDirectory);

queue put(DUMMY);//执行到这里说明指定的目录下文件已被遍历完

} catch (InterruptedException e) {

}

}

// 将指定目录下的所有文件以File对象的形式放入阻塞队列中

public void enumerate(File directory) throws InterruptedException {

File[] files = directory listFiles();

for (File file : files) {

if (file isDirectory())

enumerate(file);

else

//将元素放入队尾 如果队列满 则阻塞

queue put(file);

}

}

}

class SearchTask implements Runnable {

private BlockingQueueFile queue;

private String keyword;

public SearchTask(BlockingQueueFile queue String keyword) {

this queue = queue;

this keyword = keyword;

}

public void run() {

try {

boolean done = false;

while (!done) {

//取出队首元素 如果队列为空 则阻塞

File file = queue take();

if (file == FileEnumerationTask DUMMY) {

//取出来后重新放入 好让其他线程读到它时也很快的结束

queue put(file);

done = true;

} else

search(file);

}

} catch (IOException e) {

e printStackTrace();

} catch (InterruptedException e) {

}

}

public void search(File file) throws IOException {

Scanner in = new Scanner(new FileInputStream(file));

int lineNumber = ;

while (in hasNextLine()) {

lineNumber++;

String line = in nextLine();

if (ntains(keyword))

System out printf( %s:%d:%s%n file getPath() lineNumber

line);

}

in close();

}

lishixinzhi/Article/program/Java/hx/201311/26657

java priorityqueue 哪些方法

1.下表显示了jdk1.5中的阻塞队列的操作:

add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常

remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常

element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常

offer 添加一个元素并返回true 如果队列已满,则返回false

poll 移除并返问队列头部的元素 如果队列为空,则返回null

peek 返回队列头部的元素 如果队列为空,则返回null

put 添加一个元素 如果队列满,则阻塞

take 移除并返回队列头部的元素 如果队列为空,则阻塞

remove、element、offer 、poll、peek 其实是属于Queue接口。

2.阻塞队列的操作可以根据它们的响应方式分为以下三类:aad、removee和element操作在你试图为一个已满的队列增加元素或从空队列取得元素时 抛出异常。当然,在多线程程序中,队列在任何时间都可能变成满的或空的,所以你可能想使用offer、poll、peek方法。这些方法在无法完成任务时 只是给出一个出错示而不会抛出异常。

注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的。

3.还有带超时的offer和poll方法变种,例如,下面的调用:

boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);

尝试在100毫秒内向队列尾部插入一个元素。如果成功,立即返回true;否则,当到达超时进,返回false。同样地,调用:

Object head = q.poll(100, TimeUnit.MILLISECONDS);

如果在100毫秒内成功地移除了队列头元素,则立即返回头元素;否则在到达超时时,返回null。

4.最后,我们有阻塞操作put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。

java.ulil.concurrent包提供了阻塞队列的4个变种。默认情况下,LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎么会受阻呢),但是也可以选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。

ArrayBlockingQueue在构造时需要指定容量, 并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。

PriorityBlockingQueue是一个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。


分享名称:阻塞队列的java代码 java等待队列和阻塞队列
网页网址:http://ybzwz.com/article/hhsipg.html