并发编程学习案例-模拟抢红包

news2024/11/16 8:20:50

一、前言

再来系统动手学习一下Java并发编程。
知识点:CountDownLatch 的发令枪使用模式;红包均分,最后一个分不完的解决方法
抢红包的需求,每个红包均分,最后一个除外
1. 设置红包总额
2. 设置红包的个数
3. 模拟抢红包的人数 (细节:涉及余额分配 10元3个人抢,得把钱分完)
4. 抢红包,同一时间多个人可以同时开始 (细节:要保证同时开始)

二、代码案例

package com.lvzb.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 抢红包案例
 *
 * @author: lvzb31988
 * @date: 2023/01/09 20:00
 */
@Slf4j
public class GrabRedEnvelopeTest {

    public static void main(String[] args) throws InterruptedException {

        int totalAmount;
        int num;
        int peopleNum;
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入红包金额:");
        totalAmount = scanner.nextInt();
        System.out.println("请输入拆分多少个红包:");
        num = scanner.nextInt();
        System.out.println("请输入多少个人抢:");
        peopleNum = scanner.nextInt();
        RedEnvelope redEnvelope = new RedEnvelope(totalAmount, num, countDownLatch);

//        for (int i = 1; i <= peopleNum; i++) {
//            new Thread(redEnvelope, "第" + i + "个人").start();
//        }
//        countDownLatch.countDown();

        ExecutorService pool = Executors.newFixedThreadPool(peopleNum);
        for (int i = 1; i <= peopleNum; i++) {
            pool.execute(redEnvelope);
        }
        countDownLatch.countDown();
        // 不关闭池的话,程序不会结束
        pool.shutdown();
    }

    /**
     * 抢红包的需求,每个红包均分,最后一个除外
     * 1. 设置红包总额
     * 2. 设置红包的个数
     * 3. 模拟抢红包的人数 (细节:涉及余额分配 10元3个人抢,得把钱分完)
     * 4. 抢红包,同一时间多个人可以同时开始 (细节:要保证同时开始)
     */
    public static class RedEnvelope implements Runnable {
        /**
         * 红包总额
         */
        private int totalAmount;
        /**
         * 红包个数
         */
        private int num;
        /**
         * 每个红包均分的 额度
         */
        private int eachAmount;
        /**
         * 特殊处理最后一个红包的额度,防止分不完
         */
        private int lastAmount;

        // countDownLatch 的发令枪模式
        private CountDownLatch countDownLatch;
        // 保证线程安全
        private Object lock = new Object();

        public RedEnvelope(int totalAmount, int num, CountDownLatch countDownLatch) {
            this.totalAmount = totalAmount;
            this.num = num;
            this.countDownLatch = countDownLatch;
            this.eachAmount = totalAmount / num;
            // 最后一个红包金额 =  总额 - (红包总数-1)* 每个红包的数
            this.lastAmount = totalAmount - (num - 1) * eachAmount;
        }

        @Override
        public void run() {
            synchronized (lock) {
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    // 如果当前线程异常,就可以通知线程应该中断了
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }
                int currentAmount;
                if (num != 1) {
                    currentAmount = eachAmount;
                } else {
                    currentAmount = lastAmount;
                }
                if (num > 0) {
                    num--;
                    System.out.println(Thread.currentThread().getName() + ": hhhh 我抢到了" + currentAmount + "元...");
                } else {
                    System.out.println(Thread.currentThread().getName() + ": 没有抢到,错过一个亿...");
                }
            }
        }
    }
}

输出结果参考

在这里插入图片描述
在这里插入图片描述

参考资料

  • Java 最新版并发编程入门与春晚抢红包实战
  • CountDownLatch的使用场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/150851.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图文结合带你搞懂MySQL日志之relay log(中继日志)

GreatSQL社区原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本&#xff0c;使用上与MySQL一致。作者&#xff1a; KAiTO文章来源&#xff1a;GreatSQL社区原创 什么是中继日志&#xff08;relay log&#xff09; 中继日志&a…

线程,协程,异步编程模型

线程,协程,异步编程模型 1.线程编程模型 我们知道线程是 cpu 调度的基本单位。 如果是一个单核的cpu, 而且现在有3个线程需要执行。那么可能是 线程 1, 2, 3 通过 cpu分片&#xff0c; 轮流执行。 那么 如果不将 cpu 进行分片&#xff0c; 而是 线程 1,2,3 轮流执行&#x…

Springboot中如何优雅的写好controller层代码

前言优雅&#xff1f;看到这个词&#xff0c;我第一反应是什么是优雅&#xff1f;怎么写才算优雅&#xff1f;一千个读者有一千个哈姆雷特&#xff0c;每个人的经验、阅历不同&#xff0c;也许理解就不同。我对优雅的理解很简单&#xff0c;就是简洁有效、容易理解&#xff0c;…

递归、迭代、单向快排的实现和两种优化方法

目录 快速排序 实现代码​​​​​​​ 时间复杂度 快排的优化 随机选择策略 三位取中法 非递归的快排 单向快排 快速排序 快速排序算法是基于分治策略的一个排序算法&#xff0c;其基本思想是对于输入的子数组进行分解、递归求解&#xff0c;最后合并。 分解&#xff…

Fiddler - 夜神模拟器证书安装App抓包

Fiddler- 夜神模拟器证书安装App抓包 文章目录Fiddler- 夜神模拟器证书安装App抓包前言一、软件安装1.Openssl安装1.1下载安装1.2配置环境变量1.3查看openssl版本&#xff0c;输入命令&#xff1a;openssl version2.夜神模拟器安装1.1 下载安装1.2工具准备&#xff0c;MT管理器…

React相关扩展一(setState、lazyLoad、Hooks相关)(九)

系列文章目录 第一章&#xff1a;React基础知识&#xff08;React基本使用、JSX语法、React模块化与组件化&#xff09;&#xff08;一&#xff09; 第二章&#xff1a;React基础知识&#xff08;组件实例三大核心属性state、props、refs&#xff09;&#xff08;二&#xff0…

基于轻量级CNN的WHDLD多标签遥感分类识别系统

WHDLD数据成像波段包括R、G、B波段&#xff0c;数据覆盖包括6类地貌&#xff1a;裸地、建筑物、人行道、道路、植被、水域。数据集中包含4940张遥感影像及对应地物分类标记样本&#xff0c;影像大小为256x256像素&#xff0c;影像以jpg格式存储&#xff0c;标签数据格式为单通道…

高级前端常考手写面试题合集

解析 URL Params 为对象 let url http://www.domain.com/?useranonymous&id123&id456&city%E5%8C%97%E4%BA%AC&enabled; parseParam(url) /* 结果 { user: anonymous,id: [ 123, 456 ], // 重复出现的 key 要组装成数组&#xff0c;能被转成数字的就转成数字…

React(coderwhy)- 09(项目实战 - 1)

创建React项目 ◼ 创建项目的方式&#xff1a;create-react-app ◼ 项目配置:  配置项目的icon  配置项目的标题  配置jsconfig.json 新建jsconfig.json文件&#xff0c;在文件中粘贴以下内容{"compilerOptions": {"target": "es5","…

【数据结构趣味多】循环队列

目录 函数介绍及模拟实现 Front()函数 Rear()函数 enQueue()函数 deQueue()函数 isEmpty()函数 isFull()函数 循环队列模拟题 定义&#xff1a;把队列的头尾相连接的的顺序存储结构称为循环队列&#xff1b;循环队列的是由顺序表实现的。 为什么要使用循环队列&#…

Android MVVM之SavedStateHandle数据保存之详解与使用。

一、介绍 SavedStateHandle从名字可以看出&#xff0c;是保存状态的。这个类常和MVVM中的ViewModel搭配使用&#xff0c;对页面生命周期的数据状态的缓存与恢复做一个容器。这个容易相对onSaveInstanceState(Bundle)要更强一点&#xff0c;保存的数据类型也比较丰富&#xff0c…

算法刷题打卡第60天:回文链表

回文链表 难度&#xff1a;简单 给定一个链表的 头节点 head &#xff0c;请判断其是否为回文链表。 如果一个链表是回文&#xff0c;那么链表节点序列从前往后看和从后往前看是相同的。 示例 1&#xff1a; 输入: head [1,2,3,3,2,1] 输出: true示例 2&#xff1a; 输入:…

文本摘要,基于Pytorch和Hugging Face Transformers构建示例,有源码

​ 文本摘要的常见问题和解决方法概述&#xff0c;以及使用Hugging Face Transformers库构建基于新浪微博数据集的文本摘要示例。 作 者丨程旭源 学习笔记 1 前言简介 文本摘要旨在将文本或文本集合转换为包含关键信息的简短文本。主流方法有两种类型&#xff0c;抽取式和生…

Nodejs模块的封装(数据库Mysql)

文章目录项目结构本次演示需要使用的第三方包为1.app.js相关配置2.router下的user.js相关配置3.db/index.js文件相关操作4.router_handler下的user.js相关操作项目结构 后面的项目相关文件的创建步骤按照我写的博客从上往下一步一步来 本次演示需要使用的第三方包为 "cor…

【操作系统实验/Golang】实验4:虚拟内存页面置换算法

目录 1 实验问题描述 2 测试数据 3 流程图 4 实验结果 4 实验代码 1 实验问题描述 设计程序模拟先进先出FIFO&#xff0c;最佳置换OPT和最近最久未使用LRU页面置换算法的工作过程。 假设内存中分配给每个进程的最小物理块数为m&#xff0c;在进程运行过程中要访问的页面个…

【Leetcode面试常见题目题解】1. 两数相加

题目描述 本文是leetcode第2题的题解&#xff0c;题目描述摘自leetcode。如下 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个…

海外服务器提供商选择中存在哪些风险?

开展海外业务时&#xff0c;毫无疑问&#xff0c;选择一个高质量的海外服务器提供商可以省去不少麻烦。但是&#xff0c;同时有一些海外服务商需要避开。毕竟一个服务器不靠谱&#xff0c;这跟提供商有很大的原因。下面主要是关于低于标准的海外服务器提供商的一些潜在风险。 1…

ES6中字符串和数组新增的方法

ES6中字符串和数组新增的方法一、字符串中新增的方法1、模板字符串 (表达式、函数的调用、变量)2、repeat(次数)函数 : 将目标字符串重复N次&#xff0c;返回一个新的字符串&#xff0c;不影响目标字符串3、includes()函数 :判断字符串中是否含有指定的子字符串&#xff0c;返回…

mysql 8 新旧密码可以同时生效

在MySQL8.0以前版本&#xff0c;给MySQL更改密码&#xff0c;明确写到开发规范中&#xff0c;拒绝更在线更改更密码&#xff0c;因为在8.0以前操作非常麻烦且不太完美。 MySQL 8.0之前的处理方法&#xff1a; 1. 创建一个同样权限的帐号通过 show grants for ‘user_name’1…

通用vue编辑按钮和新建按钮事件逻辑

一、编辑按钮对话框 1.首先先创建一个文件夹page-model&#xff0c;在里面使用elemengt-plus提供的对话框组件el-dialog。 2.在page-model里面去使用之前封装好的form表单&#xff0c;就是之前封装好的搜索组件的hy-form 3.在form组件里面加一个插槽&#xff0c;对应 page-m…