Java实现抢红包功能
采用多线程模拟多人同时抢红包。服务端将玩家发出的红包保存在一个队列里,然后用Job定时将红包信息推送给玩家。每一批玩家的抢红包请求,其实操作的都是从队列中弹出的第一个红包元素,但当前的红包数量为空的时候,自动弹出下一个红包(如果有的话)。
关键思想:
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()这个方法,由于是自动弹出队首元素,必须做好同步机制,否则,当多个请求同时操作某一个红包的最后一次剩余时,会造成总的红包数量不正确。
(将加锁的代码注释后,会发现打印的总数量有可能不正确了!)
Java实现抢红包功能的更多相关文章
- 【Java EE 学习 21 下】【 使用易宝支付接口实现java网上支付功能】
一.网上支付分为两种情况,一种方法是使用直接和银行的支付接口,另外一种方法是使用第三方支付平台和银行对接完成支付. 1.直接和银行对接. 2.使用第三方支付平台 3.常见的第三方支付平台 二.使用易宝 ...
- 【Servlet】java web 文件下载功能实现
需求:实现一个具有文件下载功能的网页,主要下载压缩包和图片 两种实现方法: 一:通过超链接实现下载 在HTML网页中,通过超链接链接到要下载的文件的地址 <!DOCTYPE html> & ...
- Java 7 新增功能
Java 7 新增功能如下: 对二进制整数的支持,以0b或0B开头. 在数值中可以使用下划线,不管是整型数值,还是浮点型数值,都可以自由地使用下划线,这样可以直观地分辨数值常量中到底包含多少位.如:3 ...
- Java:延迟功能的Robot在Lunix系统上会报错
Java:延迟功能的Robot在Lunix系统上会报错 关于延迟功能的Robot: 今天开发过程中发现,本机开发好的项目,部署到Lunix服务器竟然报错!查了代码发现: Robot r = new R ...
- Atitit.java swing打印功能 api attilax总结
Atitit.java swing打印功能 api attilax总结 1. 打印方式有三种:2 1.1. 一是不经过任何修改,直接调用javascript中的window.print()打印.2 ...
- java实现验证码功能
java实现验证码功能 通过java代码实现验证码功能的一般思路: 一.通过java代码生成一张验证码的图片,将验证码的图片保存到项目中的指定文件中去,代码如下: package com.util; ...
- Java实现打印功能-AWT Graphics2D
Java实现打印功能 用java实现打印,java.awt中提供了一些打印的API,要实现打印,首先要获得打印对象,然后继承Printable实现接口方法print,以便打印机进行打印,最后用用Gra ...
- Java 14 新功能介绍
不做标题党,认认真真写个文章. 文章已经收录在 Github.com/niumoo/JavaNotes 和未读代码博客,点关注,不迷路. Java 14 早在 2019 年 9 月就已经发布,虽然不是 ...
- 超详细 Java 15 新功能介绍
点赞再看,动力无限.微信搜「程序猿阿朗 」,认认真真写文章. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Java 15 在 2 ...
随机推荐
- composer install 或 update 速度慢的解决方案(composer加速)
我们在使用composer install和composer update时,有的时候安装和更新速度非常慢,我们可以通过下面的几个方法来解决这个问题. 首先查看一下当前的 composer 全局配置地 ...
- 蓝牙5.0芯片NRF52810和NRF52832可进行mesh组网
提供智能化mesh照明解决方案,在现有传统灯具的基础上,插入NRF52832/52810的照明Mesh模块,可以迅速升级现有的传统灯具,配合手机APP和服务器系统,使每一盏灯成为物联网的一个智能节点, ...
- 使用@media实现移动端使用@2x,@3x切换
/*dpr比值为1的css代码 */ div{ width:300px; height:200px; background:url(img/button@1x.png) ; } /* dpr比值为 ...
- 移动开发在路上-- IOS移动开发系列 网络交互四(1)
最近一段时间上班忙的没日没夜的,不是披星戴月,就是头天早上出门,第二天早上回家...一直没出处时间来更新博客,码农之苦,说了都是泪,废话不多说,直接本主题,经过之前三篇的讲述,ios开发的东西大家或多 ...
- Python元组tuple(不可变)
Python元组Tuple(不可变): 元组的特点: 1.元组的初始化: tuple = (1, ) #元组只有一个元素的话,初始化时要加,否则当做元素的普通变量类型处理 tuple = (1, 2 ...
- SpringMvc 跨域处理
导读 由于浏览器对于JavaScript的同源策略的限制,导致A网站(Ajax请求)不能通过JS去访问B网站的数据,于是跨域问题就出现了. 跨域指的是域名.端口.协议的组合不同就是跨域. http:/ ...
- Java并发编程系列-(6) Java线程池
6. 线程池 6.1 基本概念 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题:如果并发的请求数 ...
- Unity5优秀插件分享
转载请标明原文地址:http://www.cnblogs.com/zhangyukof/p/6836001.html 天空盒:1.SkyboxesUnity4中自带的天空盒,经常用到.不知道为什么U ...
- CodeForces - 556C Case of Matryoshkas (水题)
Andrewid the Android is a galaxy-famous detective. He is now investigating the case of vandalism at ...
- PWN INTEGER OVERFLOW 整数溢出
0x00 Preview Last few passage I didn't conclude some important points and a general direction o ...