使用线程安全的、带有延迟元素的列表
来源:互联网 发布:mac怎么更改字体大小 编辑:程序博客网 时间:2024/06/09 23:02
概述
DelayedQueue类是Java API提供的一种有趣的数据结构,并且你可以用在并发应用程序中。在这个类中,你可以存储带有激活日期的元素。方法返回或抽取队列的元素将忽略未到期的数据元素。它们对这些方法来说是看不见的。
为了获取这种行为,你想要存储到DelayedQueue类中的元素必须实现Delayed接口。这个接口允许你处理延迟对象,所以你将实现存储在DelayedQueue对象的激活日期,这个激活时期将作为对象的剩余时间,直到激活日期到来。这个接口强制实现以下两种方法:
- compareTo(Delayed o):Delayed接口继承Comparable接口。如果执行这个方法的对象的延期小于作为参数传入的对象时,该方法返回一个小于0的值。如果执行这个方法的对象的延期大于作为参数传入的对象时,该方法返回一个大于0的值。如果这两个对象有相同的延期,该方法返回0。
- getDelay(TimeUnit unit):该方法返回与此对象相关的剩余延迟时间,以给定的时间单位表示。TimeUnit类是一个枚举类,有以下常量:DAYS、HOURS、 MICROSECONDS、MILLISECONDS、 MINUTES、 NANOSECONDS 和 SECONDS。
实例代码
Main.java
package com.packtpub.java7.concurrency.chapter6.recipe05.core;import java.util.Date;import java.util.concurrent.DelayQueue;import java.util.concurrent.TimeUnit;import com.packtpub.java7.concurrency.chapter6.recipe05.task.Event;import com.packtpub.java7.concurrency.chapter6.recipe05.task.Task;/** * Main method of the example. Execute five tasks and then * take the events of the delayed queue when they are activated * */public class Main { /** * @param args */ public static void main(String[] args) throws Exception { /* * Delayed queue to store the events */ DelayQueue<Event> queue=new DelayQueue<>(); /* * An array to store the Thread objects that execute the tasks */ Thread threads[]=new Thread[5]; /* * Create the five tasks */ for (int i=0; i<threads.length; i++){ Task task=new Task(i+1, queue); threads[i]=new Thread(task); } /* * Execute the five tasks */ for (int i=0; i<threads.length; i++) { threads[i].start(); } /* * Wait for the finalization of the five tasks */ for (int i=0; i<threads.length; i++) { threads[i].join(); } /* * Write the results to the console */ do { int counter=0; Event event; do { event=queue.poll(); if (event!=null) counter++; } while (event!=null); System.out.printf("At %s you have read %d events\n",new Date(),counter); TimeUnit.MILLISECONDS.sleep(500); } while (queue.size()>0); }}
Event.java
package com.packtpub.java7.concurrency.chapter6.recipe05.task;import java.util.Date;import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;/** * This class implements an event for a delayed queue. * */public class Event implements Delayed { /** * Date when we want to activate the event */ private Date startDate; /** * Constructor of the class * @param startDate Date when we want to activate the event */ public Event (Date startDate) { this.startDate=startDate; } /** * Method to compare two events * 实现compareTo()方法。它接收一个Delayed对象作为参数。返回当前对象的延期与作为参数传入对象的延期之间的差异。 */ @Override public int compareTo(Delayed o) { long result=this.getDelay(TimeUnit.NANOSECONDS)-o.getDelay(TimeUnit.NANOSECONDS); if (result<0) { return -1; } else if (result>0) { return 1; } return 0; } /** * Method that returns the remaining time to the activation of the event * 实现getDelay()方法。返回对象的startDate与作为参数接收的TimeUnit的真实日期之间的差异。 */ @Override public long getDelay(TimeUnit unit) { Date now=new Date(); long diff=startDate.getTime()-now.getTime(); return unit.convert(diff,TimeUnit.MILLISECONDS); }}
Task.java
package com.packtpub.java7.concurrency.chapter6.recipe05.task;import java.util.Date;import java.util.concurrent.DelayQueue;/** * This class implements a taks that store events in a delayed queue * */public class Task implements Runnable { /** * Id of the task */ private int id; /** * Delayed queue to store the events */ private DelayQueue<Event> queue; /** * Constructor of the class. It initializes its attributes * @param id Id of the task * @param queue Delayed queue to store the events */ public Task(int id, DelayQueue<Event> queue) { this.id=id; this.queue=queue; } /** * Main method of the task. It generates 100 events with the * same activation time. The activation time will be the execution * time of the thread plus the id of the thread seconds * 实现run()方法。首先,计算任务将要创建的事件的激活日期。添加等于对象ID的实际日期秒数。 */ @Override public void run() { Date now=new Date(); Date delay=new Date(); delay.setTime(now.getTime()+(id*1000)); //当前时间延迟一秒 System.out.printf("Thread %s: %s\n",id,delay); for (int i=0; i<100; i++) { Event event=new Event(delay); queue.add(event); } }}
结果
Thread 3: Sun Jul 24 23:17:32 CST 2016
Thread 4: Sun Jul 24 23:17:33 CST 2016
Thread 2: Sun Jul 24 23:17:31 CST 2016
Thread 1: Sun Jul 24 23:17:30 CST 2016
Thread 5: Sun Jul 24 23:17:34 CST 2016
At Sun Jul 24 23:17:29 CST 2016 you have read 0 events
At Sun Jul 24 23:17:29 CST 2016 you have read 0 events
At Sun Jul 24 23:17:30 CST 2016 you have read 100 events
At Sun Jul 24 23:17:30 CST 2016 you have read 0 events
At Sun Jul 24 23:17:31 CST 2016 you have read 100 events
At Sun Jul 24 23:17:31 CST 2016 you have read 0 events
At Sun Jul 24 23:17:32 CST 2016 you have read 100 events
At Sun Jul 24 23:17:32 CST 2016 you have read 0 events
At Sun Jul 24 23:17:33 CST 2016 you have read 100 events
At Sun Jul 24 23:17:33 CST 2016 you have read 0 events
At Sun Jul 24 23:17:34 CST 2016 you have read 100 events
注意:你必须十分小心size()方法。它返回列表中的所有元素数量,包含激活与未激活元素。
工作原理
在这个指南中,我们已实现Event类。这个类只有一个属性(表示事件的激活日期),实现了Delayed接口,所以,你可以在DelayedQueue类中存储Event对象。
getDelay()方法返回在实际日期和激活日期之间的纳秒数。这两个日期都是Date类的对象。你已使用getTime()方法返回一个被转换成毫秒的日期,你已转换那个值为作为参数接收的TimeUnit。DelayedQueue类使用纳秒工作,但这一点对于你来说是透明的。
对于compareTo()方法,如果执行这个方法的对象的延期小于作为参数传入的对象的延期,该方法返回小于0的值。如果执行这个方法的对象的延期大于作为参数传入的对象的延期,该方法返回大于0的值。如果这两个对象的延期相等,则返回0。
你同时实现了Task类。这个类有一个整数属性id。当一个Task对象被执行,它增加一个等于任务ID的秒数作为实际日期,这是被这个任务存储在DelayedQueue类的事件的激活日期。每个Task对象使用add()方法存储100个事件到队列中。
最后,在Main类的main()方法中,你已创建5个Task对象,并用相应的线程来执行它们。当这些线程完成它们的执行,你已使用poll()方法将所有元素写入到控制台。这个方法检索并删除队列的第一个元素。如果队列中没有任务到期的元素,这个方法返回null值。你调用poll()方法,并且如果它返回一个Evnet类,你增加计数器。当poll()方法返回null值时,你写入计数器的值到控制台,并且令线程睡眠半秒等待更多的激活事件。当你获取存储在队列中的500个事件,这个程序执行结束。
扩展
DelayQueue类提供其他有趣方法,如下:
- clear():这个方法删除队列中的所有元素。
- offer(E e):E是代表用来参数化DelayQueue类的类。这个方法插入作为参数传入的元素到队列中。
- peek():这个方法检索,但不删除队列的第一个元素。
- take():这具方法检索并删除队列的第一个元素。如果队列中没有任何激活的元素,执行这个方法的线程将被阻塞,直到队列有一些激活的元素。
转自: ifeve
- 使用线程安全的、带有延迟元素的列表
- java并发编程实战第六章(5)使用带有延迟元素的线程安全列表
- 线程安全的延迟初始化
- Java并发编程-32-带有延迟元素的队列-DelayQueue
- 线程安全的延迟初始化方式
- 线程安全的实现延迟初始化的方案
- 带有延迟的斜率优化pku3709
- DOS批处理,灵活延迟,带有参数的延迟 (copied)
- 带有安全认证的webservice
- 带有安全认证的webservice
- 带有安全认证的webservice
- 使用Structs标签处理带有html标签元素的字符串
- 线程安全的AtomicLong使用
- 线程安全的AtomicLong使用
- 线程安全的AtomicLong使用
- java并发编程第六章(4)使用基于优先级的阻塞式线程安全列表
- 使用Adapter更新列表延迟的现象解析
- 用Collections.synchronizedCollection创建线程安全的集合、列表...
- 枚举优化程序
- 数据库优化
- 2.go开源groupcache项目——关于protobuf
- 3.go开源groupcache项目——consistenthash代码
- Mysql执行语句优化
- 使用线程安全的、带有延迟元素的列表
- ajax跨域问题总结
- RGB颜色对照表
- URAL1009 K-based Numbers
- java自带定时任务功能(Timer&TimerTask)
- 基于 flask 框架的模拟instagram 图片分享网站的开发 7 (爬虫机器人)
- unity3d 第十三天
- git push 后 gitweb不能查看git 仓库(权限问题)
- http://elf8848.iteye.com/blog/382528