- 浏览: 54572 次
- 性别:
- 来自: 上海
最新评论
-
HappyBoyLi:
谢谢分享,在jvm中怎么看-Xms是1M,-Xmx是64M参数 ...
java client VM 和java server VM
【转载自http://milk-36.iteye.com/blog/617155】
Java 1.5版本最终提供了对编程中最基础数据结构之一-Queue的内在支持。本文章将探究新添加到java.util包中的Queue接口,演示如何去使用这个新特性去使你的数据处理流式化。
by Kulvir Singh Bhogal (Translated by Victor Jan 2004-09-26 )
(英文原文见http://www.devx.com/Java/Article/21983/1954?pf=true )
在计算机学科中,基础数据结构之一 — Queue。你会想起Queue是一种数据结构,在它里边的元素可以按照添加它们的相同顺序被移除。在以前的Java版本中,这中FIFO(先进先出)数据结构很不幸被忽略了。随着Java1.5(也叫Tiger)的出现,对Queue支持第一次成为固有特性。
过去在没有Queue的情况下如何管理?
在Java 1.5以前,通常的实现方式是使用java.util.List 集合来模仿Queue。Queue的概念通过把对象添加(称为enqueuing的操作)到List的尾部(即Queue的后部)并通过从List的头部(即Queue的前部)提取对象而从List中移除(称为dequeuing的操作)来模拟。下面代码显示了你以前可能做法。
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Vector;
public class QueueEmulate
{
private LinkedList queueMembers;
public Object enqueue(Object element)
{
queueMembers.add (element);
return element;
}
public Object dequeue()
{
return queueMembers.removeFirst();
}
}
现在我们有了Queue
Java 1.5在java.util包中 新添加了Queue接口,下面代码中使用到它(从 sample code 的SimpleQueueUsageExample.java 截取)。注意,在Java 1.5中,java.util.LinkedList被用来实现java.util.Queue,如同java.util.List接口。也要注意我是如何显式地声明我的只包含字符串的Queue---使用<String> 泛型(如果需要深入了解泛型,请参阅"J2SE 1.5: Java's Evolution Continues ")。这样使我省却了当从 Queue 中提取它们时不得不进行对象造型的痛苦。
Queue<String> myQueue = new LinkedList<String>();
myQueue.add("Add Me");
myQueue.add("Add Me Too");
String enqueued = myQueue.remove();
你可以看到LinkedList类的add和remove方法被分别用于执行enqueuing和dequeuing操作。实际上没有更好的可用方法;Queue接口提供了新的offer和poll方法,如下显示(截取自SimpleQueueUsageExamplePreferred ):
Queue<String> myQueue = new LinkedList<String>();
boolean offerSuccess;
// offer method tries to enqueue.
// A boolean is returned telling you if the
// attempt to add to the queue was successful or not
offerSuccess=myQueue.offer("Add Me");
offerSuccess=myQueue.offer("Add Me Too");
// peek at the head of the queue, but don't grab it
Object pull = myQueue.peek();
String enqueued = null;
// grab the head of the queue
if (pull!=null) enqueued = myQueue.poll();
System.out.println(enqueued);
如果你的Queue有固定长度限制(常常是这种情形),使用add方法向Queue中添加内容,将导致抛出一个非检查异常。当你编译SimpleQueueUsageExample的代码时,编译器将会就此问题发出警告。相反,当新的offer方法试图添加时,如果一切正常则会返回TRUE,否则,返回FALSE。 同样地, 如果你试图使用remove方法对一个空Queue操作时 ,也将导致一个非检查异常。
你也可以使用poll方法去从Queue中提取元素。如果在Queue中没有元素存在,poll方法将会返回一个null(即不会抛出异常)。在某些情况下,你可能不想提取头部的元素而只是想看一下。Queue接口提供了一个peek方法来做这样的事情。如果你正在处理一个空Queue,peek方法返回 null。象add-offer和remove-poll关系一样,还有peek-element关系。在Queue为空的情形下,element方法抛出一个非检查异常。但如果在Queue中有元素,peek方法允许你查看一下第一个元素而无需真的把他从Queue中取出来。peek方法的用法在SimpleQueueUsageExamplePreferred类中有示例。
AbstractQueue类
如你所见,java.util.LinkedList类实现了java.util.Queue接口,同样,AbstractQueue也是这样。 AbstractQueue 类实现了java.util接口的一些方法(因此在它的名字中包含abstract)。而AbstractQueue将重点放在了实现offer,poll和peek方法上。另外使用一些已经提供的具体实现。
PriorityQueue类
在 PriorityQueue中,当你添加元素到Queue中时,实现了自动排序。根据你使用的PriorityQueue的不同构造器,Queue元素的顺序要么基于他们的自然顺序要么通过PriorirtyQueue构造器传入的Comparator来确定。下面的代码示例了PirorityQueue 类的使用方法。在Queue的前边是字符串"Alabama"-由于元素在PriorityQueue中是按自然顺序排列的(此例中是按字母表顺序)。
PriorityQueue<String> priorityQueue = new PriorityQueue<String>();
priorityQueue.offer("Texas");
priorityQueue.offer("Alabama");
priorityQueue.offer("California");
priorityQueue.offer("Rhode Island");
int queueSize = priorityQueue.size();
for (int i =0; i< queueSize; i++)
{
System.out.println(priorityQueue.poll());
}
执行结果如下:
Alabama
California
Rhode Island
Texas
Queue各项按照自然顺序-字母顺序-来排列
。
如上提到的,你可以创建你自己的Comparator类并提供给PirorityQueue。如此,你可以定义你自己的排序方式。在PriorityQueueComparatorUsageExample 类中可找到此方式,在其中使用了一个名为State的助手类。如你在下边看到的,在类定义中,State只简单地包含了一个名字和人口。
private String name;
private int population;
public State(String name, int population)
{
super();
this.name = name;
this.population = population;
}
public String getName()
{
return this.name;
}
public int getPopulation()
{
return this.population;
}
public String toString()
{
return getName() + " - " + getPopulation();
}
在PriorityQueueComparatorUsageExample中,Queue使用了java.util.Comparator的自定义实现来定义排列顺序(如下)。
PriorityQueue<State> priorityQueue =
new PriorityQueue(6, new Comparator<State>()
{
public int compare(State a, State b)
{
System.out.println("Comparing Populations");
int populationA = a.getPopulation();
int populationB = b.getPopulation();
if (populationB>populationA)
return 1;
else if (populationB<populationA)
return -1;
else
return 0;
}
}
);
执行PriorityQueueComparatorUsageExample 类后,添加到Queue中的State对象将按人口数量排放(从低到高)。
阻塞Queue
Queue通常限定于给定大小。迄今为止,通过Queue的实现你已经看到,使用offer或add方法enqueue Queue(并用remove或poll来dequeue Queue)都是假设如果Queue不能提供添加或移除操作,那么你不需要等待程序执行。java.util.concurrent.BlockingQueue接口实现阻塞。它添加了put和take方法。举一个例子可能更有用。
使用原来的producer/consumer关系来假定你的producer写一个Queue(更特定是一个BlockingQueue)。你有一些 consumer正从Queue中读取,在一个有序的方式下,哪种方式是你希望看到的。基本上,每个consumer需要等待先于它并获准从Queue中提取项目的前一个consumer。用程序构建此结构,先生成一个producer线程用于向一个Queue中写数据,然后生成一些consumer线程从同一Queue中读取数据。注意,线程会阻塞另一线程直到当前线程做完从Queue中提取一项的操作。
下面的代码展示了类Producer写BlockingQueue的过程。注意run方法中的对象(你有责任实现,因为你继承了Thread)在等待了随机数量的时间(范围从100到500毫秒)后,被放进了BlockingQueue。放到Queue中的对象只是一些包含消息产生时的时间的字符串。
添加对象的实际工作是由如下语句实现的:
blockingQueue.put("Enqueued at: " + time)
put方法会抛出InterruptedException,因此,put操作需要被try...catch块包围,用来捕获被抛出的异常 (见Listing 1 )。
从producer中提取消息的是Consumer对象,它也继承自Thread对象并因此要实现run方法(见Listing 2 )。
Consumer 类在设计上是类似于Producer类的。Consumer类使用take方法去从Queue中取出(即dequeue)消息,而不是将消息放到 BlockingQueue中。如前所述,这需要等待到有什么内容确实存在于Queue中时才发生。如果producer线程停止放置(即 enqueue)对象到Queue中,那么consumer将等待到Queue的项目有效为止。下面所示的TestBlockingQueue类,产生四个consumer线程,它们从BlockingQueue中尝试提取对象。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class TestBlockingQueue
{
public static void main(String args[])
{
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<String>();
Producer producer = new Producer(blockingQueue, System.out);
Consumer consumerA = new Consumer("ConsumerA", blockingQueue, System.out);
Consumer consumerB = new Consumer("ConsumerB", blockingQueue, System.out);
Consumer consumerC = new Consumer("ConsumerC", blockingQueue, System.out);
Consumer consumerD = new Consumer("ConsumerD", blockingQueue, System.out);
producer.start();
consumerA.start();
consumerB.start();
consumerC.start();
consumerD.start();
}
}
Figure 1. Consumer Threads: These threads dequeue messages from the BlockingQueue in the order that you spawned them.
下面一行创建BlockingQueue:
BlockingQueue<String> blockingQueue
= new LinkedBlockingQueue<String>();
注意,它使用BlockingQueue的LinkedBlockingQueue实现。这是因为BlockingQueue是一个抽象类,你不能直接实例化它。你也可以使用ArrayBlockingQueueQueue类型。 ArrayBlockingQueue使用一个数组作为它的存储设备,而LinkedBlockingQueue使用一个LinkedList。 ArrayBlockingQueue的容量是固定的。对于LinkedBlockingQueue,最大值可以指定;默认是无边界的。本示例代码采用无边界方式。
在类的执行期间,从Queue中读取对象以顺序方式执行(见下面例子的执行)。实际上,一个consumer线程阻塞其他访问BlockingQueue的线程直到它可以从Queue中取出一个对象。
DelayQueue-我是/不是不完整的
在某些情况下,存放在Queue中的对象,在它们准备被取出之前,会需要被放在另一Queue中一段时间。这时你可使用java.util.concurrent.DelayQueue类,他实现类BlockingQueue接口。DelayQueue需要Queue对象被驻留在Queue上一段指定时间。
我想用来证实它的现实例子(这可能是你非常渴望的)是关于松饼(muffins)。噢,Muffin对象(象我们正在谈论的Java-没有coffee双关意图)。假定你有一个DelayQueue并在其中放了一些Muffin对象。Muffin对象(如下所示)必须实现java.util.concurrent.Delayed 接口,以便可被放在DelayQueue中。这个接口需要Muffin对象实现getDelay方法(如下所示)。getDelay方法,实际上声明给多长时间让对象保存在DelayQueue中。当该方法返回的值变为0或小于0时,对象就准备完毕(或在本例子中,是烤制完毕)并允许被取出(见 Listing 3 )。
Muffin类也实现compareTo(java.util.concurrent.Delayed)方法。由于Delayed接口继承自 java.lang.Comparable 类,这通过约定限制你要实现Muffin对象的bakeCompletion时间。
由于你不是真想去吃没有完全烤熟的Muffin,因此,需要将Muffin放在DelayQueue中存放推荐的烤制时间。Listing 4 ,取自DelayQueueUsageExample类,展示了从DelayQueue中enqueue和dequeue Muffin对象。
如你所见,对Muffin对象的烤制时间是使用它的构造器设置的(构造器期望烤制时间是以秒计)。
如前所讲,Muffin对象放到DelayQueue中是不允许被取出的,直到他的延时时间(又叫烤制时间)超期。元素被从Queue中取出基于最早的延时时间。在本例中,如果你有一些已经烤过的Muffin对象,他们将按他们已经等待多久而被取出(换句话说,最早被烤制的Muffin会在新烤制的 Muffin之前被取出)。
SynchronousQueue
在Java 1.5中,另外一种阻塞Queue实现是SynchronousQueue。相当有趣的是,该Queue没有内在容量。这是故意的,因为Queue意在用于传递目的。这意味着,在一个同步Queue结构中,put请求必须等待来自另一线程的给SynchronousQueue的take请求。同时,一个 take请求必须等待一个来自另一线程的给SynchronousQueue的put请求。用程序来示例此概念,可参见示例代码。类似于前边的 LinkedBlockingQueue例子,它包含一个consumer(SynchConsumer),见Listing 5 。
Listing 5 中的代码使用SynchronousQueue类的 poll(long timeout,TimeUnit unit)方法。此方法允许poll过程在厌倦等待另一消费线程写SynchronousQueue之前等待一个指定时间(本例中是20秒)。
在Listing 6 中的producer(SynchProducer )使用相似的offer(E o,long timeout, TimeUnit unit)方法去放置对象到SynchronousQueue中。使用此方法允许在 厌倦等待另一线程去读取SynchronousQueue之前等待一段时间(本例中为10秒) 。
TestSynchQueue 展示了producer和consumer的动作:
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class TestSynchQueue
{
public static void main(String args[])
{
SynchronousQueue<String> synchQueue = new SynchronousQueue<String>();
SynchProducer producer = new SynchProducer("ProducerA",synchQueue, System.out);
SynchConsumer consumerA = new SynchConsumer("ConsumerA", synchQueue, System.out);
consumerA.start();
producer.start();
}
}
当试图明白隐藏在SynchronousQueue后面的概念时,要牢记这些Queue通常被使用在什么地方。JavaDoc中关于同步Queue指出:
"它们[同步Queue]是适合于传递设计,在那里运行在一个线程中的对象必须与运行在另外一个线程中的对象同步以便于交给它一些信息,时间或任务。"
Java 1.5版本最终提供了对编程中最基础数据结构之一-Queue的内在支持。本文章将探究新添加到java.util包中的Queue接口,演示如何去使用这个新特性去使你的数据处理流式化。
by Kulvir Singh Bhogal (Translated by Victor Jan 2004-09-26 )
(英文原文见http://www.devx.com/Java/Article/21983/1954?pf=true )
在计算机学科中,基础数据结构之一 — Queue。你会想起Queue是一种数据结构,在它里边的元素可以按照添加它们的相同顺序被移除。在以前的Java版本中,这中FIFO(先进先出)数据结构很不幸被忽略了。随着Java1.5(也叫Tiger)的出现,对Queue支持第一次成为固有特性。
过去在没有Queue的情况下如何管理?
在Java 1.5以前,通常的实现方式是使用java.util.List 集合来模仿Queue。Queue的概念通过把对象添加(称为enqueuing的操作)到List的尾部(即Queue的后部)并通过从List的头部(即Queue的前部)提取对象而从List中移除(称为dequeuing的操作)来模拟。下面代码显示了你以前可能做法。
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Vector;
public class QueueEmulate
{
private LinkedList queueMembers;
public Object enqueue(Object element)
{
queueMembers.add (element);
return element;
}
public Object dequeue()
{
return queueMembers.removeFirst();
}
}
现在我们有了Queue
Java 1.5在java.util包中 新添加了Queue接口,下面代码中使用到它(从 sample code 的SimpleQueueUsageExample.java 截取)。注意,在Java 1.5中,java.util.LinkedList被用来实现java.util.Queue,如同java.util.List接口。也要注意我是如何显式地声明我的只包含字符串的Queue---使用<String> 泛型(如果需要深入了解泛型,请参阅"J2SE 1.5: Java's Evolution Continues ")。这样使我省却了当从 Queue 中提取它们时不得不进行对象造型的痛苦。
Queue<String> myQueue = new LinkedList<String>();
myQueue.add("Add Me");
myQueue.add("Add Me Too");
String enqueued = myQueue.remove();
你可以看到LinkedList类的add和remove方法被分别用于执行enqueuing和dequeuing操作。实际上没有更好的可用方法;Queue接口提供了新的offer和poll方法,如下显示(截取自SimpleQueueUsageExamplePreferred ):
Queue<String> myQueue = new LinkedList<String>();
boolean offerSuccess;
// offer method tries to enqueue.
// A boolean is returned telling you if the
// attempt to add to the queue was successful or not
offerSuccess=myQueue.offer("Add Me");
offerSuccess=myQueue.offer("Add Me Too");
// peek at the head of the queue, but don't grab it
Object pull = myQueue.peek();
String enqueued = null;
// grab the head of the queue
if (pull!=null) enqueued = myQueue.poll();
System.out.println(enqueued);
如果你的Queue有固定长度限制(常常是这种情形),使用add方法向Queue中添加内容,将导致抛出一个非检查异常。当你编译SimpleQueueUsageExample的代码时,编译器将会就此问题发出警告。相反,当新的offer方法试图添加时,如果一切正常则会返回TRUE,否则,返回FALSE。 同样地, 如果你试图使用remove方法对一个空Queue操作时 ,也将导致一个非检查异常。
你也可以使用poll方法去从Queue中提取元素。如果在Queue中没有元素存在,poll方法将会返回一个null(即不会抛出异常)。在某些情况下,你可能不想提取头部的元素而只是想看一下。Queue接口提供了一个peek方法来做这样的事情。如果你正在处理一个空Queue,peek方法返回 null。象add-offer和remove-poll关系一样,还有peek-element关系。在Queue为空的情形下,element方法抛出一个非检查异常。但如果在Queue中有元素,peek方法允许你查看一下第一个元素而无需真的把他从Queue中取出来。peek方法的用法在SimpleQueueUsageExamplePreferred类中有示例。
AbstractQueue类
如你所见,java.util.LinkedList类实现了java.util.Queue接口,同样,AbstractQueue也是这样。 AbstractQueue 类实现了java.util接口的一些方法(因此在它的名字中包含abstract)。而AbstractQueue将重点放在了实现offer,poll和peek方法上。另外使用一些已经提供的具体实现。
PriorityQueue类
在 PriorityQueue中,当你添加元素到Queue中时,实现了自动排序。根据你使用的PriorityQueue的不同构造器,Queue元素的顺序要么基于他们的自然顺序要么通过PriorirtyQueue构造器传入的Comparator来确定。下面的代码示例了PirorityQueue 类的使用方法。在Queue的前边是字符串"Alabama"-由于元素在PriorityQueue中是按自然顺序排列的(此例中是按字母表顺序)。
PriorityQueue<String> priorityQueue = new PriorityQueue<String>();
priorityQueue.offer("Texas");
priorityQueue.offer("Alabama");
priorityQueue.offer("California");
priorityQueue.offer("Rhode Island");
int queueSize = priorityQueue.size();
for (int i =0; i< queueSize; i++)
{
System.out.println(priorityQueue.poll());
}
执行结果如下:
Alabama
California
Rhode Island
Texas
Queue各项按照自然顺序-字母顺序-来排列
。
如上提到的,你可以创建你自己的Comparator类并提供给PirorityQueue。如此,你可以定义你自己的排序方式。在PriorityQueueComparatorUsageExample 类中可找到此方式,在其中使用了一个名为State的助手类。如你在下边看到的,在类定义中,State只简单地包含了一个名字和人口。
private String name;
private int population;
public State(String name, int population)
{
super();
this.name = name;
this.population = population;
}
public String getName()
{
return this.name;
}
public int getPopulation()
{
return this.population;
}
public String toString()
{
return getName() + " - " + getPopulation();
}
在PriorityQueueComparatorUsageExample中,Queue使用了java.util.Comparator的自定义实现来定义排列顺序(如下)。
PriorityQueue<State> priorityQueue =
new PriorityQueue(6, new Comparator<State>()
{
public int compare(State a, State b)
{
System.out.println("Comparing Populations");
int populationA = a.getPopulation();
int populationB = b.getPopulation();
if (populationB>populationA)
return 1;
else if (populationB<populationA)
return -1;
else
return 0;
}
}
);
执行PriorityQueueComparatorUsageExample 类后,添加到Queue中的State对象将按人口数量排放(从低到高)。
阻塞Queue
Queue通常限定于给定大小。迄今为止,通过Queue的实现你已经看到,使用offer或add方法enqueue Queue(并用remove或poll来dequeue Queue)都是假设如果Queue不能提供添加或移除操作,那么你不需要等待程序执行。java.util.concurrent.BlockingQueue接口实现阻塞。它添加了put和take方法。举一个例子可能更有用。
使用原来的producer/consumer关系来假定你的producer写一个Queue(更特定是一个BlockingQueue)。你有一些 consumer正从Queue中读取,在一个有序的方式下,哪种方式是你希望看到的。基本上,每个consumer需要等待先于它并获准从Queue中提取项目的前一个consumer。用程序构建此结构,先生成一个producer线程用于向一个Queue中写数据,然后生成一些consumer线程从同一Queue中读取数据。注意,线程会阻塞另一线程直到当前线程做完从Queue中提取一项的操作。
下面的代码展示了类Producer写BlockingQueue的过程。注意run方法中的对象(你有责任实现,因为你继承了Thread)在等待了随机数量的时间(范围从100到500毫秒)后,被放进了BlockingQueue。放到Queue中的对象只是一些包含消息产生时的时间的字符串。
添加对象的实际工作是由如下语句实现的:
blockingQueue.put("Enqueued at: " + time)
put方法会抛出InterruptedException,因此,put操作需要被try...catch块包围,用来捕获被抛出的异常 (见Listing 1 )。
从producer中提取消息的是Consumer对象,它也继承自Thread对象并因此要实现run方法(见Listing 2 )。
Consumer 类在设计上是类似于Producer类的。Consumer类使用take方法去从Queue中取出(即dequeue)消息,而不是将消息放到 BlockingQueue中。如前所述,这需要等待到有什么内容确实存在于Queue中时才发生。如果producer线程停止放置(即 enqueue)对象到Queue中,那么consumer将等待到Queue的项目有效为止。下面所示的TestBlockingQueue类,产生四个consumer线程,它们从BlockingQueue中尝试提取对象。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class TestBlockingQueue
{
public static void main(String args[])
{
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<String>();
Producer producer = new Producer(blockingQueue, System.out);
Consumer consumerA = new Consumer("ConsumerA", blockingQueue, System.out);
Consumer consumerB = new Consumer("ConsumerB", blockingQueue, System.out);
Consumer consumerC = new Consumer("ConsumerC", blockingQueue, System.out);
Consumer consumerD = new Consumer("ConsumerD", blockingQueue, System.out);
producer.start();
consumerA.start();
consumerB.start();
consumerC.start();
consumerD.start();
}
}
Figure 1. Consumer Threads: These threads dequeue messages from the BlockingQueue in the order that you spawned them.
下面一行创建BlockingQueue:
BlockingQueue<String> blockingQueue
= new LinkedBlockingQueue<String>();
注意,它使用BlockingQueue的LinkedBlockingQueue实现。这是因为BlockingQueue是一个抽象类,你不能直接实例化它。你也可以使用ArrayBlockingQueueQueue类型。 ArrayBlockingQueue使用一个数组作为它的存储设备,而LinkedBlockingQueue使用一个LinkedList。 ArrayBlockingQueue的容量是固定的。对于LinkedBlockingQueue,最大值可以指定;默认是无边界的。本示例代码采用无边界方式。
在类的执行期间,从Queue中读取对象以顺序方式执行(见下面例子的执行)。实际上,一个consumer线程阻塞其他访问BlockingQueue的线程直到它可以从Queue中取出一个对象。
DelayQueue-我是/不是不完整的
在某些情况下,存放在Queue中的对象,在它们准备被取出之前,会需要被放在另一Queue中一段时间。这时你可使用java.util.concurrent.DelayQueue类,他实现类BlockingQueue接口。DelayQueue需要Queue对象被驻留在Queue上一段指定时间。
我想用来证实它的现实例子(这可能是你非常渴望的)是关于松饼(muffins)。噢,Muffin对象(象我们正在谈论的Java-没有coffee双关意图)。假定你有一个DelayQueue并在其中放了一些Muffin对象。Muffin对象(如下所示)必须实现java.util.concurrent.Delayed 接口,以便可被放在DelayQueue中。这个接口需要Muffin对象实现getDelay方法(如下所示)。getDelay方法,实际上声明给多长时间让对象保存在DelayQueue中。当该方法返回的值变为0或小于0时,对象就准备完毕(或在本例子中,是烤制完毕)并允许被取出(见 Listing 3 )。
Muffin类也实现compareTo(java.util.concurrent.Delayed)方法。由于Delayed接口继承自 java.lang.Comparable 类,这通过约定限制你要实现Muffin对象的bakeCompletion时间。
由于你不是真想去吃没有完全烤熟的Muffin,因此,需要将Muffin放在DelayQueue中存放推荐的烤制时间。Listing 4 ,取自DelayQueueUsageExample类,展示了从DelayQueue中enqueue和dequeue Muffin对象。
如你所见,对Muffin对象的烤制时间是使用它的构造器设置的(构造器期望烤制时间是以秒计)。
如前所讲,Muffin对象放到DelayQueue中是不允许被取出的,直到他的延时时间(又叫烤制时间)超期。元素被从Queue中取出基于最早的延时时间。在本例中,如果你有一些已经烤过的Muffin对象,他们将按他们已经等待多久而被取出(换句话说,最早被烤制的Muffin会在新烤制的 Muffin之前被取出)。
SynchronousQueue
在Java 1.5中,另外一种阻塞Queue实现是SynchronousQueue。相当有趣的是,该Queue没有内在容量。这是故意的,因为Queue意在用于传递目的。这意味着,在一个同步Queue结构中,put请求必须等待来自另一线程的给SynchronousQueue的take请求。同时,一个 take请求必须等待一个来自另一线程的给SynchronousQueue的put请求。用程序来示例此概念,可参见示例代码。类似于前边的 LinkedBlockingQueue例子,它包含一个consumer(SynchConsumer),见Listing 5 。
Listing 5 中的代码使用SynchronousQueue类的 poll(long timeout,TimeUnit unit)方法。此方法允许poll过程在厌倦等待另一消费线程写SynchronousQueue之前等待一个指定时间(本例中是20秒)。
在Listing 6 中的producer(SynchProducer )使用相似的offer(E o,long timeout, TimeUnit unit)方法去放置对象到SynchronousQueue中。使用此方法允许在 厌倦等待另一线程去读取SynchronousQueue之前等待一段时间(本例中为10秒) 。
TestSynchQueue 展示了producer和consumer的动作:
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class TestSynchQueue
{
public static void main(String args[])
{
SynchronousQueue<String> synchQueue = new SynchronousQueue<String>();
SynchProducer producer = new SynchProducer("ProducerA",synchQueue, System.out);
SynchConsumer consumerA = new SynchConsumer("ConsumerA", synchQueue, System.out);
consumerA.start();
producer.start();
}
}
当试图明白隐藏在SynchronousQueue后面的概念时,要牢记这些Queue通常被使用在什么地方。JavaDoc中关于同步Queue指出:
"它们[同步Queue]是适合于传递设计,在那里运行在一个线程中的对象必须与运行在另外一个线程中的对象同步以便于交给它一些信息,时间或任务。"
发表评论
文章已被作者锁定,不允许评论。
-
js framework
2012-05-16 15:25 853本文重点为大家介绍16款非常实用的JavaScript库,涵 ... -
oracle 学习笔记(1)
2011-07-09 23:24 912--更改用户口令alter user test identif ... -
javascript中匿名函数
2011-06-22 14:12 1162以下内容从其他博客摘录而来: 一、什么是匿名函数? ... -
oracle dual表详解
2011-04-22 14:37 1413ORACLE DUAL表详解 ORACL ... -
java client VM 和java server VM
2011-04-11 11:01 13723转载自:http://blog.csdn. ... -
jquery学习网站
2011-03-31 10:07 921http://www.learningjquery.com/ ... -
java多线程下的单例模式
2011-02-26 17:11 1359转载自:http://xupo.iteye.com/blog/ ... -
[Java]IEEE754浮点数的转换方法
2011-02-22 21:41 501816进制浮点数的表示方 ... -
unicode字符编码标准
2011-02-22 14:47 1518转载自:http://blog.csdn.ne ... -
java中的堆栈回顾
2011-02-21 23:26 723java中堆栈(stack)和堆(heap ... -
常用的正则表达式
2011-02-21 17:59 327017种正则表达式 "^\d+$" ... -
JDK中的设计模式
2011-02-21 16:02 1386转载自:http://www.iteye.co ... -
java位运算
2011-02-21 15:54 954Java 位运算[转] 一,Java ... -
struts2的安全漏洞及解决办法
2011-02-21 10:49 1681转自:http://www.iteye.com/topic/7 ... -
有关ConcurrentModificationException
2011-02-16 18:06 1077当使用 fail-fast iterator 对 Collec ...
相关推荐
这篇学习笔记将深入探讨Java多线程的核心概念、实现方式以及相关工具的使用。 一、多线程基础 1. 线程与进程:在操作系统中,进程是资源分配的基本单位,而线程是程序执行的基本单位。每个进程至少有一个主线程,...
本学习笔记将深入探讨Java多线程的相关知识,包括其原理、实现方式、同步机制以及常见问题。 ### 一、多线程的基本概念 多线程是指在一个程序中存在两个或更多的执行线程,这些线程共享同一内存空间,但各自拥有...
本笔记全面涵盖了多线程的学习,包括基础理论和实践代码,旨在帮助开发者深入理解并掌握Java多线程技术。 一、线程基础知识 线程是操作系统分配CPU时间的基本单位,一个进程中可以包含多个线程。Java通过`Thread`类...
生产者消费者模型是常见的多线程协作模式,通过`BlockingQueue`等工具实现线程间的通信和同步。死锁是指两个或更多线程相互等待对方释放资源而无法继续执行的情况,应避免创建这样的循环等待。线程之间的数据传递...
### Java多线程编程总结 #### 一、Java多线程概述 Java多线程是Java编程语言中不可或缺的一部分,它允许程序同时处理多个任务,从而显著提高应用程序的性能和响应速度。Java5之前的版本虽然支持多线程,但在语言...
本笔记将深入探讨JUC的相关知识点,帮助开发者理解并掌握Java多线程的核心概念。 首先,我们来了解一下Java线程。线程是程序执行的基本单元,允许多个任务在同一时间运行,从而提高了系统资源的利用率。在Java中,...
在Java编程领域,多线程和并发处理是不可或缺的一部分,特别是在设计高性能、高...通过深入学习这份"Java并发实践-学习笔记",开发者能够提升自己在处理多线程和并发问题上的能力,从而设计出更高效、更稳定的应用。
以下是对马士兵多线程笔记的详细解析。 1. **多线程基础**:多线程是指一个应用程序中同时执行多个线程(即任务)的能力。这种并发执行可以提高系统资源的利用率,提升程序的响应速度和执行效率,特别是在多核...
Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,提高了系统的效率和响应性。在本文中,我们将深入探讨Java多线程的相关知识点,并结合提供的源代码进行学习。 1. **线程的创建** - **实现...
Java多线程是Java编程中的核心概念,它允许并发执行多个任务,提高程序的执行效率。以下是关于Java多线程的详细知识点: 1. **创建线程** - **继承Thread类**:创建一个新的类,该类继承自Thread类,并重写run()...
"concurrentTang"项目显然是一个专注于Java多线程与高并发学习的资源集合,其中包含了作者的学习笔记和相关代码示例。通过这个项目,开发者可以深入理解并掌握Java在并发环境下的编程技巧。 Java多线程允许程序同时...
《Java并发编程实践》这本书是Java开发者...这些知识点构成了Java并发编程的基础,理解和掌握它们对于编写高效、稳定的多线程Java应用程序至关重要。在实际编程中,要根据具体需求灵活应用,并注意性能和安全性的平衡。
总的来说,Java并发编程实践中的任务执行是一个涉及线程调度、线程池管理、任务生命周期控制、结果处理等多个方面的复杂主题。理解和掌握这些概念和技术,能够帮助开发者编写出更加高效、可靠的并发程序。
│ 高并发编程第一阶段05讲、采用多线程方式模拟银行排队叫号.mp4 │ 高并发编程第一阶段06讲、用Runnable接口将线程的逻辑执行单元从控制中抽取出来.mp4 │ 高并发编程第一阶段07讲、策略模式在Thread和Runnable...
《Java 7 Concurrency Cookbook》是一本专注于...以上知识点是《Java 7 Concurrency Cookbook》中可能涉及的核心内容,通过深入学习和实践,开发者可以提升在多线程环境下的编程技能,编写出更加高效、稳定的并发程序。
Java并发编程是Java开发中的重要领域,它涉及到多线程、同步、锁机制、线程池等关键概念,是提高程序性能和效率的关键技术。在Java中,并发编程的运用可以充分利用多核处理器的能力,实现高效的多任务处理。以下是对...
在Java线程中,同步是非常重要的概念,用于解决多线程环境下的数据安全问题。Java提供了多种同步机制,包括synchronized关键字、Lock接口(如ReentrantLock)以及java.util.concurrent包中的并发工具类(如Semaphore...
《Java并发编程实践》学习笔记 Java并发编程是Java开发者必须掌握的重要技能,尤其是在多核处理器和高并发应用中。本书《Java Concurrency In Practice》是Java并发编程的经典之作,由Brian Goetz、Tim Peierls、...
在Java编程领域,并发编程是一项至关重要的技能,特别是在多线程环境和分布式系统中。这份机构内训资料,通过“Java并发体系学习思维笔记”,为我们揭示了Java并发编程的核心概念、最佳实践以及常见问题的解决策略。...