Java多线程实现简易微信发红包的方法实例

网友投稿 240 2022-11-04


Java多线程实现简易微信发红包的方法实例

一、

首先我们先大致了解一下什么是多线程。(书上的解释)

程序是一段静态的代码,它是应用软件的蓝本。进程是程序的一次动态执行过程,对应了从代码加载执行,执行到执行完毕的一个完整的过程。

线程不是进程,线程是比进程更小的执行单位,一个进程在其执行过程中,可以产生多个线程形成多条执行线索,每条线索即每个线程也有它自身的产生,存在,消亡的过程,和进程共享操作系统的资源类似,线程间也可以共享进程中的某些内存单元,并利用这些共享单元来实现数据交换,实时通信与必要的同步操作,但与进程不同的是线程的中断和恢复更加节省开支。线程是运行在进程中的“小进程”。

多线程是指一个应用程序中同时存在几个执行体,按几条不同的执行线索共同工作的情况。虽然看似是几个事件同时发生,但其实计算机在任何给定时刻只能执行那些线程中的一个。为了建立这些线程在同步进行的感觉,java虚拟机快速的把控制从一个线程切换到另一个线程。这些线程将被轮流执行,使得每个线程都有机会使用CPU资源。

二、

利用单线程实现的简易微信发红包

共写有三种方法,其中第一种,第二种未设置范围,红包数和人数为一一对应,第三种增添了取值范围以及计数器,人多红包少有未抢到现象发生。

(1) 方法一

import java.util.Scanner;

import com.sun.deploy.security.SelectableSecurityManager;

import java.util.Random;

public class 简易微信发红包 {

public static void main(String[] args) {

Scanner scanner=new Scanner(System.in);

int n;

double money;

System.out.println("请输入您想要发的红包数量");

n=scanner.nextInt();

System.out.println("请输入您发送的红包金额");

money=scanner.nextDouble();

T2 t2=new T2(n,money);

t2.Rob();

}

}

class T2 {

public double remain;//有红包被领取后的余额

int n;//红包数量

T2(int n,double money) {

this.remain=money;

this.n=n;

}

int a=1;

public void Rob() {

while (n > 0) {

double x2;

if (n != 1) {//因为最后一个人领取金额为前面人领取红包后剩下的,所以无需再进行随机

x2 = process();//取随机金额

while (judge(x2) != 1) {//判断取到的随机金额是否非法,即无法保证后来每个红包领取者领到最低金额0.01

x2 = process();//若非法则重新取随机金额

}

remain = remain - x2;//当领取成功后余额减去领走的金额

n--;//确保每次判断人数为所剩红包数减1

System.out.println("红包获得者" + a + "获得" + x2 + "元");//此处默认领取者顺序为升序

a++;//控制输出顺序

}

else {

x2 = remain;//因为最后一个人领取金额为前面人领取红包后剩下的,所以无需再进行随机

String str = String.valueOf(x2);

String str1 = String.format("%.2f", x2);

x2 = Double.parseDouble(str1);

System.out.println("红包获得者" + a + "获得" + x2 + "元");

n--;//确保每次判断人数为所剩红包数减1

}

}

}

public int judge(double x){//判断函数

if(remain-x>(n-1)*0.01){//确保后来红包领取者最少能领到最低金额0.01

return 1;

}

else return 0;

}

public double process() {//实现红包金额随机的函数

double x2;

double x1;

String str1;

Random random = new Random();//随机数为取0到1之间的任意double值

x1 = remain*random.nextDouble();

str1= String.format("%.2f",x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x2=Double.parseDouble(str1);//再将字符串型数据转换成double型

while(x2==0){//如果所取金额非法则回炉重造

x1 = remain*random.nextDouble();

str1= String.format("%.2f",x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x2=Double.parseDouble(str1);//再将字符串型数据转换成double型

}

return x2;

}

}

程序运行结果如下

(2) 方法二

import java.util.Random;

import java.util.Scanner;

public class 简易微信发红包2 {

public static void main(String[] args) {

Scanner scanner=new Scanner(System.in);

double money=0;//红包总金额

int n;//红包个数

System.out.println("请输入您想要发的红包数量");

n=scanner.nextInt();

System.out.println("请输入您发送的红包金额");

money=scanner.nextDouble();

if(money/n==0.01){//当所发金额刚好为每人0.01元时

T6 t6=new T6(money,n);

t6.Rob();

}else{

T5 t5=new T5(money,n);

t5.Rob();

}

}

}

class T5{

double remain;

int n;

T5(double money,int n){

this.remain=money;

this.n=n;

}

int a=1;

public void Rob(){

double max;//最大可领红包金额

double x1;//随机金额

double x2;//所得金额

while(n>0) {

if (n != 1) {//前n-1个红包领取者领的红包为随机金额红包

max = remain - (n - 1) * 0.01;//最大可领红包金额为剩下的人都获得最小金额0.01

Random random = new Random();

x1 = (double) random.nextInt((int) ((max - 0.01) * 100));

//用nextInt而不用nextDouble的原因是nextDouble无法设置seed

//上式中max-0.01,下面的x2+0.01即解决了随机数取0导致红包获得者没抢到钱的问题

x1 /= 100.0;

x2 = x1 + 0.01;

remain = remain - x2;

n--;

System.out.println("红包获得者" + a + "获取金额为:" + String.format("%.2f", x2) + "元");

a++;

} else {//最后一人领的红包为前n-1个人领完后剩下的红包

System.out.println("红包获得者" + a + "获取金额为:" + String.format("%.2f", remain) + "元");

n--;

}

}

}

}

class T6 {

double remain;

int n;

T6(double money,int n){

this.remain=money;

this.n=n;

}

public void Rob(){

for(int i=1;i<=n;i++){

System.out.println("红包获得者"+i+"获得了0.01元");

}

}

}

程序运行结果如下:

(3) 方法三

import java.util.Random;

import java.util.Scanner;

public class 简易微信发红包3 {

public static void main(String[] args) {

int p,n;

double money;

System.out.println("请输入您发送的红包金额");

Scanner scanner=new Scanner(System.in);

money=scanner.nextDouble();

System.out.println("请输入您发送的红包数量");

n=scanner.nextInt();

System.out.println("请输入参与抢红包的人数");

p=scanner.nextInt();

T7 t7=new T7(money,n,p);

t7.Rob();

}

}

class T7 {

double money;

int n,p;

int count =0;//计数器

double remain;

T7(double money,int n,int p){

this.money=money;//总金额

this.n=n;//红包数

this.p=p;//抢红包人数

this.remain=money;//所剩金额

}

public void Rob() {

for(int i=1;i<=p;i++) {

double x1, x2, d;

String s1, s2;

Random random = new Random();

d = money / (n - 1);//设置范围让每次所得金额不超过总数的1/(n-1),这样也就避免了一次取得过大导致后面抢的红包不能保证每个最少0.01

x1 = d * random.nextDouble();

s1 = String.format("%.2f", x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x1 = Double.parseDouble(s1);//再将字符串型数据转换成double型

while (x1 == 0 || x1 == money / (n - 1)) {

x1 = d * random.nextDouble();

s1 = String.format("%.2f", x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x1 = Double.parseDouble(s1);//再将字符串型数据转换成double型

}

s2 = String.format("%.2f", remain);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

remain = Double.parseDouble(s2);//再将字符串型数据转换成double型

if (count < n - 1) {//前n-1个红包金额为随机金额

System.out.println( "红包抢夺者"+i+ "抢到了" + s1 + "元");

remain -= x1;

count++;

} else if (count == n - 1) {//第n个为前n-1个红包抢完所剩金额

System.out.println( "红包抢夺者"+i+ "抢到了" + s2 + "元");

count++;

} else if (count > n - 1) {//红包被抢完后再来的

System.out.println( "红包抢夺者"+i+ "哎呀,手慢了!没抢到!");

count++;

}

}

}

}

程序运行结果如下:

三、

利用多线程实现的简易微信发红包

那么如何创建多线程呢?

1.通过继承thread类创建多线程

JDK中提供了一个线程类Thread,通过继承Thread类,并重写Thread类中的run()方法便可实现多线程。

在Thread类中,提供了一个start()方法用于启动新线程,线程启动后,系统会自动调用run()方法,如果子类重写了该方法便会执行子类中的方法。

run()方法中就是写能够被线程执行的程序。如果直接调用则相当于普通方法,必须使用start()方法,才能启动线程,然后再由JVM去调用该线程的run()方法。

创建并启动多线程的步骤

①定义Thread类的子类,并重写该类的run方法,其方法体代表线程需要完成的任务。因此常把run方法称为线程执行体。

②创建Thread子类的实例,即创建线程对象。

③用线程对象的start方法来启动该线程。

2.通过实现Runnable接口创建多线程

通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类。

Thread类提供了另外一个构造方法Thread(Runnable target),其中Runnable是一个接口,它只有一个run()方法。

当通过Thread(Runnable target))构造方法创建线程对象时,只需为该方法传递一个实现了Runnable接口的实例对象,这样创建的线程将调用实现了Runnable接口中的run()方http://法作为运行代码,而不需要调用Thread类中的run()方法。

创建并启动多线程的步骤

①定义Runnable接口的实现类,并重写该接口的run方法,该run方法的方法体同样是该线程的线程执行体。

②创建Runnable实现类的实例,并以此为实例作为Thread的参数来创建Thread对象,该Thread对象才是真正的线程对象。

当多个线程使用同一个共享资源时,可以将处理共享资源的代码放置在一个代码块中,使用synchronized关键字来修饰,被称作同步代码块:

sychronized(lock){

操作共享资源代码块

}

其中:lock是一个锁对象,它是同步代码块的关键。当线程执行同步代码块时,首先会检查锁对象的标志位,默认情况下,标志位为1,此时线程会执行同步代码块,同时将锁对象的标志位置为0。当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代码。循环往复,直到共享资源被处理完为止。

同步代码块可以有效解决线程的安全问题,当把共享资源的操作放在synchronized定义的区域内时,便为这些操作加了同步锁。

在方法前面同样可以使用synchronized关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能,具体语法格式如下:

synchronized 返回值类型 方法名 {}

被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其它线程都会发生阻塞,直到当前线程访问完毕后,其它线程才有机会执行方法。

另外

public final String getName():获取线程的名称。

public static Thread currentThread():返回当前正在执行的线程对象,这样就可以获取任意方法所在的线程名称。

Thread.currentThread().getName()

现将上面的单线程改成多线程实现

本篇文章多线程的创建以及实现用Runnable接口实现

(1)

import java.util.Scanner;

import com.sun.deploy.security.SelectableSecurityManager;

import java.util.Random;

public class 微信发红包多线程 {

public static void main(String[] args) {

Scanner scanner=new Scanner(System.in);

int n;

double money;

System.out.println("请输入您想要发的红包数量");

n=scanner.nextInt();

System.out.println("请输入您发送的红包金额");

money=scanner.nextDouble();

T3 t3=new T3(n,money);//创建runnable实现类的实例

for (int j = 1; j <= n; j++) {

new Thread(t3, "红包获得者" + j).start();//以上面创建的实例作为Thread的参数来创建Thread对象,并为Thread对象指定一个名字,用线程对象的start方法来启动该线程。

}

}

}

class T3 implements Runnable {//实现runnable接口

public double remain;//有红包被领取后的余额

int n;//红包数量

public synchronized void run() {//同步方法,在某一时刻只允许一个线程访问,防止数据错乱

Rob();

}

T3(int n, double money) {

this.remain = money;

this.n = n;

}

int a = n;

public void Rob() {

double x2;

if (n != 1) {//因为最后一个人领取金额为前面人领取红包后剩下的,所以无需再进行随机

x2 = process();//取随机金额

while (judge(x2) != 1) {//判断取到的随机金额是否非法,即是否能保证后来每个红包领取者领到最低金额0.01

x2 = process();//若非法则重新取随机金额

}

remain = remain - x2;//当领取成功后余额减去领走的金额

n--; //确保每次判断人数为红包数减一

} else {

x2 = remain;//因为最后一个人领取金额为前面人领取红包后剩下的,所以无需再进行随机

String str = String.valueOf(x2);

String str1 = String.format("%.2f", x2);

x2 = Double.parseDouble(str1);

}

Thread th = Thread.currentThread();//返回当前正在执行的线程对象

String th_name = th.getName();//获取线程的名称

System.out.println(th_name + "抢到" + x2 + "元");

}

public int judge(double x) {//判断函数

if (remain - x > (n - 1) * 0.01) {//确保后来红包领取者能领到最低金额0.01

return 1;

} else return 0;

}

public double process() {//实现红包金额随机的函数

double x2;

double x1;

String str1;

Random random = new Random();//随机数为取0到1之间的任意double值

x1 = remain * random.nextDouble();

str1 = String.format("%.2f", x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x2 = Double.parseDouble(str1);//再将字符串型数据转换成double型

while (x2 == 0) {//如果所取金额非法则回炉重造

x1 = remain * random.nextDouble();

str1 = String.format("%.2f", x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x2 = Double.parseDouble(str1);//再将字符串型数据转换成double型

}

return x2;

}

}

程序运行结果如下:

(2)

import java.util.Random;

import java.util.Scanner;

public class 简易微信发红包多线程2 {

public static void main(String[] args) {

Scanner scanner=new Scanner(System.in);

double money=0;//红包总金额

int n;//红包个数

System.out.println("请输入您想要发的红包数量");

n=scanner.nextInt();

System.out.println("请输入您发送的红包金额");

money=scanner.nextDouble();

if(money/n==0.01){//当所发金额刚好为每人0.01元时

T4 t4=new T4(money,n);

for(int i=1;i<=n;i++) {

new Thread(t4,"红包获得者"+i).start();

}

}else{

T1 t1=new T1(money,n);

for(int i=1;i<=n;i++) {

new Thread(t1,"红包获得者"+i).start();

}

}

}

}

class T1 implements Runnable{

double remain;

int n;

T1(double money,int n){

this.remain=money;

this.n=n;

}

@Override

public synchronized void run() {

Rob();

}

public void Rob(){

double max;//最大可领红包金额

double x1;//随机金额

double x2;//所得金额

if(n!=1) {//前n-1个红包领取者领的红包为随机金额红包

max=remain-(n-1)*0.01;//最大可领红包金额为剩下的人都获得最小金额0.01

Random random=new Random();

x1=(double)random.nextInt((int) ((max-0.01)*100));

//用nextInt而不用nextDouble的原因是nextDouble无法设置seed

//上式中max-0.01,下面的x2+0.01即解决了随机数取0导致红包获得者没抢到钱的问题

x1/=100.0;

x2=x1+0.01;

remain=remain-x2;

n=n-1;

Thread th=Thread.currentThread();//获取当前线程

String th_name=th.getName();//获取线程名字

System.out.println(th_name+"获取金额为:"+String.format("%.2f", x2)+"元");

}

else {//最后一人领的红包为前n-1个人领完后剩下的红包

Thread th=Thread.currentThread();//获取当前线程

String th_name=th.getName();//获取线程名字

System.out.println(th_name+"获取金额为:"+String.format("%.2f", remain)+"元");

}

}

}

class T4 implements Runnable{

double remain;

int n;

T4(double money,int n){

this.remain=money;

this.n=n;

}

public synchronized void run() {

Rob();

}

public void Rob(){

Thread th=Thread.currentThread();//获取当前线程

String th_name=th.getName();//获取线程名字

System.out.println(th_name+"获取金额为:"+String.format("%.2f", remain/n)+"元");

}

}

程序运行结果如下:

(3)

import java.util.Random;

import java.util.Scanner;

public class 简易微信发红包多线程3 {

public static void main(String[] args) {

int p,n;

double money;

System.out.println("请输入您发送的红包金额");

Scanner scanner=new Scanner(System.in);

money=scanner.nextDouble();

System.out.println("请输入您发送的红包数量");

n=scanner.nextInt();

System.out.println("请输入参与抢红包的人数");

p=scanner.nextInt();

HH hh=new HH(money,n);

for (int i=1;i<=p;i++){

new Thread(hh,"第"+i+"个人").start();

}

}

}

class HH implements Runnable{

double money;

int n;

int count =0;//计数器

double remain;

HH(double money,int n){

this.money=money;//总金额

this.n=n;//红包数

this.remain=money;//所剩金额

}

@Override

public synchronized void run() {

Rob();

}

public void Rob(){

double x1,x2,d;

String s1,s2;

Thread th=Thread.currentThread();//获取当前线程

String th_name=th.getName();//获取线程名字

Random random=new Random();

d=money/(n-1);//设置范围让每次所得金额不超过总数的1/(n-1),这样也就避免了一次取得过大导致后面抢的红包不能保证每个最少0.01

x1=d*random.nextDouble();

s1=String.format("%.2f",x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x1 = Double.parseDouble(s1);//再将字符串型数据转换成double型

while(x1==0||x1==money/(n-1)){

x1=d*random.nextDouble();

s1=String.format("%.2f",x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

x1 = Double.parseDouble(s1);//再将字符串型数据转换成double型

}

s2= String.format("%.2f",remain);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位

remain = Double.parseDouble(s2);//再将字符串型数据转换成double型

if (count

System.out.println(th_name+"抢到了"+s1+"元");

remain-=x1;

count++;

}else if (count==n-1){//第n个为前n-1个红包抢完所剩金额

System.out.println(th_name+"抢到了"+s2+"元");

count++;

}else if (count>n-1){//红包被抢完后再来的

System.out.println(th_name+"哎呀,手慢了!没抢到!");

count++;

}

}

}

程序运行结果如下:

总结

新手上路,因能力有限,若有不足之处还望大家海涵!

System.out.println(th_name+"抢到了"+s1+"元");

remain-=x1;

count++;

}else if (count==n-1){//第n个为前n-1个红包抢完所剩金额

System.out.println(th_name+"抢到了"+s2+"元");

count++;

}else if (count>n-1){//红包被抢完后再来的

System.out.println(th_name+"哎呀,手慢了!没抢到!");

count++;

}

}

}

程序运行结果如下:

总结

新手上路,因能力有限,若有不足之处还望大家海涵!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:信用卡申请进度查询API(信用卡申请进度查询中心)
下一篇:面试别人的套路
相关文章

 发表评论

暂时没有评论,来抢沙发吧~