并发编程-concurrent指南-阻塞队列-延迟队列DelayQueue
DelayQueue是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的,即队头对象的延迟到期时间最长。注意:不能将null元素放置到这种队列中。
Delayed
一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。
此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序。
下面例子是订单超时处理的具体代码:
重点是DelayOrderComponent 和OrderMessage
import com.concurrent.delayqueue.component.DelayOrderComponent;
import com.concurrent.delayqueue.model.OrderInfo;
import com.concurrent.delayqueue.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.Date; @RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService; //创建订单
@RequestMapping("insert")
public void insert() {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setCreateTime(new Date());
orderInfo.setStatus(0);
orderService.insert(orderInfo);
} //取消订单
@RequestMapping("cancel")
public void cancel(Long orderId) {
orderService.cancel(orderId);
} //支付订单
@RequestMapping("paysuccess")
public void paysuccess(Long orderId) {
orderService.paysuccess(orderId);
} //查看队列中剩余处理数
@RequestMapping("queuecount")
public int queuecount() {
return DelayOrderComponent.getDelayQueueCount();
}
}
@Service
public class OrderService {
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private DelayOrderComponent delayOrderComponent; /**
* 插入
* @param orderInfo
*/
@Transactional
public void insert(OrderInfo orderInfo){
orderInfoMapper.insert(orderInfo);
//加入到延时队列中,用于超时未支付
boolean flag = delayOrderComponent.addDelayQueue(new OrderMessage(orderInfo.getOrderId(),orderInfo.getCreateTime().getTime()));
if(!flag){
throw new RuntimeException();
}
} /**
* 取消
*/
@Transactional
public void cancel(Long orderId){
orderInfoMapper.updateByStatus(orderId,0,-1);
delayOrderComponent.removeDelayQueue(orderId);
} /**
* 用户支付成功
*/
public void paysuccess(Long orderId){
orderInfoMapper.updateByStatus(orderId,0,1);
delayOrderComponent.removeDelayQueue(orderId);
} }
import com.concurrent.delayqueue.mapper.OrderInfoMapper;
import com.concurrent.delayqueue.message.OrderMessage;
import com.concurrent.delayqueue.model.OrderInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executors; /**
* 处理订单超时
*/
@Component
@Lazy(false)
public class DelayOrderComponent {
@Autowired
private OrderInfoMapper orderInfoMapper; private static DelayQueue<OrderMessage> delayQueue = new DelayQueue<OrderMessage>();
public static int getDelayQueueCount(){
return delayQueue.size();
} /**
* 系统启动时,预先加载的数据@PostConstruct
*/
@PostConstruct
public void init(){
/**初始化时加载数据库中需处理超时的订单**/
System.out.println("获取数据库中需要处理的超时的订单");
List<OrderInfo> list = orderInfoMapper.selectByStatus(0);
for(int i=0;i<list.size();i++){
OrderInfo orderInfo = list.get(i);
OrderMessage orderMessage = new OrderMessage(orderInfo.getOrderId(),orderInfo.getCreateTime().getTime());
this.addDelayQueue(orderMessage);//加入队列
} /**
* 启动线程,取延时消息
*/
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
while(true){
try {
OrderMessage orderMessage = delayQueue.take();
//处理超时订单
orderInfoMapper.updateByStatus(orderMessage.getOrderId(),0,2);//订单状态改成超时订单
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
} /**
* 加入延时队列
* 用户下单时,调用此方法
*/
public boolean addDelayQueue(OrderMessage orderMessage){
return delayQueue.add(orderMessage);
} /**
* 从延时队列中删除
* 用户主动取消,或者支付成功后,调用此方法
*/
public boolean removeDelayQueue(Long orderId){
for (Iterator<OrderMessage> iterator = delayQueue.iterator(); iterator.hasNext();) {
OrderMessage queue = iterator.next();
if(orderId.equals(queue.getOrderId())){
return delayQueue.remove(queue);
}
}
return false;
} }
public class OrderMessage implements Delayed {
private final static long DELAY = 15*60*1000L;//默认延迟15分钟 private Long orderId;//订单号
private Long expireTime;//过期时间
public OrderMessage(Long orderId,Long createTime){
this.orderId = orderId;
this.expireTime = createTime + DELAY;
} @Override
public long getDelay(TimeUnit unit) {
return unit.convert(this.expireTime - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
} @Override
public int compareTo(Delayed other) {
if (other == this){
return 0;
}
if(other instanceof OrderMessage){
OrderMessage otherRequest = (OrderMessage)other;
long otherStartTime = otherRequest.expireTime;
return (int)(this.expireTime - otherStartTime);
}
return 0;
} public Long getOrderId() {
return orderId;
} public void setOrderId(Long orderId) {
this.orderId = orderId;
} public Long getExpireTime() {
return expireTime;
} public void setExpireTime(Long expireTime) {
this.expireTime = expireTime;
}
}
import java.util.Date; public class OrderInfo {
private Long orderId;//订单状态
private Date createTime;//创建时间
private Integer status;//订单状态:0待支付1已支付-1取消2已超时 public Long getOrderId() {
return orderId;
} public void setOrderId(Long orderId) {
this.orderId = orderId;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public Integer getStatus() {
return status;
} public void setStatus(Integer status) {
this.status = status;
}
}
import com.concurrent.delayqueue.model.OrderInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import java.util.List; @Mapper
public interface OrderInfoMapper {
int deleteByPrimaryKey(Long orderId); int insert(OrderInfo record); int insertSelective(OrderInfo record); OrderInfo selectByPrimaryKey(Long orderId); int updateByPrimaryKeySelective(OrderInfo record); int updateByPrimaryKey(OrderInfo record); List<OrderInfo> selectByStatus(int status);
int updateByStatus(@Param("orderId")Long orderId, @Param("oldstatus")Integer oldstatus,@Param("newstatus")Integer newstatus);
}
OrderInfoMapper.xml <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.concurrent.delayqueue.mapper.OrderInfoMapper" >
<resultMap id="BaseResultMap" type="com.concurrent.delayqueue.model.OrderInfo" >
<id column="order_id" property="orderId" jdbcType="BIGINT" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
<result column="status" property="status" jdbcType="INTEGER" />
</resultMap>
<sql id="Base_Column_List" >
order_id, create_time, status
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select
<include refid="Base_Column_List" />
from t_order
where order_id = #{orderId,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
delete from t_order
where order_id = #{orderId,jdbcType=BIGINT}
</delete>
<insert id="insert" parameterType="com.concurrent.delayqueue.model.OrderInfo"
useGeneratedKeys="true" keyProperty="orderId">
insert into t_order (order_id, create_time, status
)
values (#{orderId,jdbcType=BIGINT}, #{createTime,jdbcType=TIMESTAMP}, #{status,jdbcType=INTEGER}
)
</insert>
<insert id="insertSelective" parameterType="com.concurrent.delayqueue.model.OrderInfo" >
insert into t_order
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="orderId != null" >
order_id,
</if>
<if test="createTime != null" >
create_time,
</if>
<if test="status != null" >
status,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="orderId != null" >
#{orderId,jdbcType=BIGINT},
</if>
<if test="createTime != null" >
#{createTime,jdbcType=TIMESTAMP},
</if>
<if test="status != null" >
#{status,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.concurrent.delayqueue.model.OrderInfo" >
update t_order
<set >
<if test="createTime != null" >
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="status != null" >
status = #{status,jdbcType=INTEGER},
</if>
</set>
where order_id = #{orderId,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="com.concurrent.delayqueue.model.OrderInfo" >
update t_order
set create_time = #{createTime,jdbcType=TIMESTAMP},
status = #{status,jdbcType=INTEGER}
where order_id = #{orderId,jdbcType=BIGINT}
</update> <select id="selectByStatus" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from t_order
where status = #{status,jdbcType=INTEGER}
</select>
<update id="updateByStatus">
update t_order
set status = #{newstatus,jdbcType=INTEGER}
where order_id = #{orderId,jdbcType=BIGINT}
and status = #{oldstatus,jdbcType=INTEGER}
</update>
</mapper>
application.properties spring.datasource.url = jdbc:mysql://localhost:3306/concurrent?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = 123456 mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml
源码地址:https://github.com/qjm201000/concurrent_delayqueue.git
数据库sql文件:到源码里面查看readme,按照步骤来就行。
并发编程-concurrent指南-阻塞队列-延迟队列DelayQueue的更多相关文章
- 并发编程-concurrent指南-阻塞双端队列BlockingDeque
java.util.concurrent 包里的 BlockingDeque 接口表示一个线程安放入和提取实例的双端队列. BlockingDeque 类是一个双端队列,在不能够插入元素时,它将阻塞住 ...
- 并发编程-concurrent指南-阻塞双端队列-链阻塞双端队列LinkedBlockingDeque
LinkedBlockingDeque是双向链表实现的阻塞队列.该阻塞队列同时支持FIFO和FILO两种操作方式,即可以从队列的头和尾同时操作(插入/删除): 在不能够插入元素时,它将阻塞住试图插入元 ...
- 并发编程-concurrent指南-阻塞队列-数组阻塞队列ArrayBlockingQueue
ArrayBlockingQueue类是实现了BlockingQueue. ArrayBlockingQueue是一个有界的阻塞队列,其内部实现是将对象放在一个数组中. 放入元素方法: (1) add ...
- 并发编程-concurrent指南-阻塞队列-链表阻塞队列LinkedBlockingQueue
LinkedBlockingQueue是一个基于链表的阻塞队列. 由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选. LinkedBlocki ...
- 并发编程-concurrent指南-阻塞队列-优先级的阻塞队列PriorityBlockingQueue
PriorityBlockingQueue是一个支持优先级的无界阻塞队列. 它使用了和类 java.util.PriorityQueue 一样的排序规则.你无法向这个队列中插入 null 值. 所有插 ...
- 并发编程-concurrent指南-阻塞队列BlockingQueue
阻塞队列BlockingQueue,java.util.concurrent下的BlockingQueue接口表示一个线程放入和提取实例的队列. 适用场景: BlockingQueue通常用于一个线程 ...
- 并发编程-concurrent指南-阻塞队列-同步队列SynchronousQueue
SynchronousQueue:同步Queue,属于线程安全的BlockingQueue的一种,此队列设计的理念类似于"单工模式",对于每个put/offer操作,必须等待一个t ...
- 并发编程-concurrent指南-原子操作类-AtomicInteger
在java并发编程中,会出现++,--等操作,但是这些不是原子性操作,这在线程安全上面就会出现相应的问题.因此java提供了相应类的原子性操作类. 1.AtomicInteger
- 并发编程-concurrent指南-线程池ExecutorService的实例
1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...
随机推荐
- ORA-00600: internal error code, arguments: [4194], [53], [41], [], [], [], [], []
真的不动,关闭同事开发测试IBM 3650server它直接关系到电源插头行??? 第二天加点重新启动之后oracle 打开报错ORA-00600: internal error code, argu ...
- 开源 自由 java CMS - FreeCMS1.9 积分规则管理
项目地址:http://www.freeteam.cn/ 积分规则管理 管理会员操作时积分处理规则. 1. 积分规则管理 从左側管理菜单点击积分规则进入. 2. 加入积分规则 在积分规则列表下方点击& ...
- 仿真算法数据结构与算法 C++实现
模拟算法:仿真的全过程,通过改变数学模型参数,进一步观察状态更改这些参数发生变化正当程序. 算法思路:利用随机函数来模拟不可预测发生在自然界.(srand() 和 rand()函数生成一个随机数) 模 ...
- socket函数集-----网络编程必备值得拥有
accept(接受socket连线) 相关函数 socket,bind,listen,connect 表头文件 #include<sys/types.h> #include<sys/ ...
- SDL(01-10)
SDL中的函数需要先初始化SDL才能用 : //Initialize SDL ) { printf( "SDL could not initialize! SDL_Error: %s\n&q ...
- 在vs2015上使用asp.net core+ef core
官方的文档https://docs.asp.net/en/latest/tutorials/first-mvc-app/start-mvc.html 先来看一下实现的效果
- Win8Metro(C#)数字图像处理--2.29图像除法运算
原文:Win8Metro(C#)数字图像处理--2.29图像除法运算 [函数名称] 图像除法函数DivisionProcess(WriteableBitmap src, WriteableBit ...
- C#数字图像处理时注意图像的未用区域
原文:C#数字图像处理时注意图像的未用区域 图1. 被锁定图像像素数组基本布局 如图1所示,数组的宽度并不一定等于图像像素数组的宽度,还有一部分未用区域.这是为了提高效率,系统要确定每 ...
- ubuntu下建立golang的build脚本
在不在os中设置gopath,goroot的情况下 建立build.sh文件,文件内容如下: export GOARCH="386"export GOBIN="/home ...
- 编译时MSIL注入--实践Mono Cecil(1)
原文:编译时MSIL注入--实践Mono Cecil(1) 紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务—MSBuild Task(csproject),在第一 ...