Java实现抢红包功能
作者:littleschemer 发布时间:2021-08-05 07:47:58
标签:java,抢红包
本文实例为大家分享了Java实现抢红包功能的具体代码,供大家参考,具体内容如下
关键思想:
1.抢红包涉及多人并发操作,需要做好同步保证多线程运行结果正确。
2.由于同时在线人数大,从性能方面考虑,玩家的发红包请求不必及时响应,而由服务端定时执行发红包队列。
下面是主要的代码和实现逻辑说明
1.创建一个类,表示红包这个实体概念。直接采用原子变量保证增减同步。Java的原子变量是一种精度更细的同步机制,在高度竞争的情况下,锁的性能将超过原子变量的性能,但在更真实的竞争情况,原子变量享有更好的性能。
public class SpringGift {
private String role;
private AtomicInteger gift;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public AtomicInteger getGift() {
return gift;
}
public void setGift(AtomicInteger gift) {
this.gift = gift;
}
public int getRemainCount(){
return this.gift.get();
}
}
2.采用多线程模拟多人同时抢红包。服务端将玩家发出的红包保存在一个队列里,然后用Job定时将红包信息推送给玩家。每一批玩家的抢红包请求,其实操作的都是从队列中弹出的第一个红包元素,但当前的红包数量为空的时候,自动弹出下一个红包(如果有的话)。
public class Test {
public static ConcurrentLinkedQueue<SpringGift> queue;
public static SpringGift currGift;
public static AtomicInteger count = new AtomicInteger();
static class myThread implements Runnable{
public void run(){
handleEvent();
}
}
public static void main(String[] args) throws Exception {
queue = new ConcurrentLinkedQueue<SpringGift>();
for(int i =0;i<3;i++){
SpringGift gift = new SpringGift();
gift.setRole("role"+i);
gift.setGift(new AtomicInteger(50));
queue.add(gift);
}
myThread mythread = new myThread();
for(int i=0;i<1000;i++){
new Thread(mythread).start();
}
System.err.println("总共收到"+count.get());
}
private static SpringGift getGift(){
//防止多条线程同时弹出队首
synchronized (queue) {//若没有加锁,打印的count总数不对!!!!
if(currGift == null || currGift.getRemainCount() <=0){
currGift = queue.poll();
}
}
return currGift;
}
public static void handleEvent(){
try{
SpringGift obj = getGift();
if(obj == null || obj.getRemainCount() <= 0){
System.err.println("没有了");
return ;
}
if(obj !=null && obj.getGift().getAndDecrement() >0 ){
System.err.println("抢到一个红包");
count.getAndIncrement();
}
Thread.sleep(500);//模拟处理其他操作
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果部分截图如下
需要注意的是,getGift()这个方法,由于是自动弹出队首元素,必须做好同步机制,否则,当多个请求同时操作某一个红包的最后一次剩余时,会造成总的红包数量不正确。
(将加锁的代码注释后,会发现打印的总数量有可能不正确了!)
来源:https://blog.csdn.net/littleschemer/article/details/46382117


猜你喜欢
- 前言在原生的 Android 或 iOS 中,都提供了基本的键值对存储方式,Android 是 SharedPreferences,iOS
- 我们在j2ee当中,连接数据库的时候经常会用到properties配置文件,我们原来在eclipse或者myeclipse当中会在src文件
- 需求:接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实体类(concrete class)?抽象类中是否
- SpringBoot控制配置类加载顺序@Configuration配置被加载进容器的方式大体上可分为3种手动:构建ApplicationCo
- 一般而言在Android上使用JAVA实现彩图转换为灰度图,与J2ME上的实现方法类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK
- 本文实例讲述了C#使用round函数四舍五入的方法。分享给大家供大家参考。具体分析如下:C#中的round函数实际上不是真正的四舍五入函数,
- 上一篇文章我们介绍了Apache Commons Math3学习之数值积分实例代码,这里给大家分享math3多项式曲线拟合的相关内容,具体如
- 1.概述在平时的开发中,有一些Jar包因为种种原因,在Maven的中央仓库中没有收录,所以就要使用本地引入的方式加入进来。2. 拷贝至项目根
- JTable的排序是一个让人头疼的问题,Sun没有为排序这个最常用的功能提供类。但是近日翻看Sun官方java的tutorial,却发现其在
- java字段值为null,不返回该字段类上打注解@JsonSerialize(include = JsonSerialize.Inclusi
- 在html中大家都知道布局是什么意思了,简单来说就是将页面划分模块,比如html中的div、table等。那么Android中也是这样的。A
- 测试参数设置:1、循环调用new A()实现堆溢出,java.lang.OutOfMemoryError: Java heap space,
- 前景概要在这个之前service_edu子模块下的功能是没有任何问题,创建了service_oss子模块之前失败了很多次,影响到了之前原本正
- 环境搭建创建Maven项目。pom.xml文件中引入RocketMQ依赖。<dependencies>  
- 目录Shiro简介Shiro快速入门SpringBoot-Shiro整合(最后会附上完整代码)附上最后的完整代码Shiro整合mybatis
- G1 – Garbage First(垃圾优先算法)G1最主要的设计目标是: 将STW停顿的时间和分布变成可预期以及可配
- 制作透明窗体办法有好几种,各有优缺点. 我们先来看看C#本身提供的办法 1:通过设置窗体的 TransparencyKey实现 例:窗体中
- Optional在JAVA中被定义为一个容器类,更确切的说只存一个元素的容器。container object which may or m
- 简单介绍如果把单链表的最后一个节点的指针指向链表头部,而不是指向NULL,那么就构成了一个单向循环链表,通俗讲就是让尾节点指向头结点。单向环
- Java InputStream的任意拷贝有时候,当我们需要多次使用到同一个InputStream的时候如何实现InputStream的拷贝