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

作者:HENU小菜鸡 时间:2023-04-16 11:46:15 

 一、

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

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

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

多线程是指一个应用程序中同时存在几个执行体,按几条不同的执行线索共同工作的情况。虽然看似是几个事件同时发生,但其实计算机在任何给定时刻只能执行那些线程中的一个。为了建立这些线程在同步进行的感觉,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;

}
}

程序运行结果如下

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

(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元");

}
}
}

程序运行结果如下:

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

(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++;
     }
   }
 }
}

程序运行结果如下:

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

三、

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

那么如何创建多线程呢?

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()方法作为运行代码,而不需要调用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;
 }
}

程序运行结果如下:

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

(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)+"元");
 }
}

程序运行结果如下:

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

(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<n-1){//前n-1个红包金额为随机金额
     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++;
   }
 }

}

程序运行结果如下:

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

总结

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

来源:https://blog.csdn.net/weixin_46569912/article/details/113308600

标签:java,多线程,发红包
0
投稿

猜你喜欢

  • android端微信支付V3版本地签名统一下单详解

    2023-05-18 02:37:44
  • 基于Android实现百度地图定位过程详解

    2021-06-12 20:55:34
  • C#使用Effects给图片增加阴影效果

    2023-09-09 14:50:18
  • c#实现万年历示例分享 万年历农历查询

    2022-11-08 23:26:57
  • 关于SpringCloudStream配置问题

    2023-08-08 20:12:00
  • Android 可拖动的seekbar自定义进度值

    2023-12-28 12:37:24
  • Android实现自定义带文字和图片Button的方法

    2021-06-20 17:13:50
  • mybatis-plus使用generator实现逆向工程

    2022-06-05 20:16:49
  • Spring Cloud Alibaba Nacos Config加载配置详解流程

    2022-03-24 23:06:01
  • java设计模式之外观模式学习笔记

    2022-07-02 18:48:06
  • java 面试题闰年判断详解及实例

    2023-11-27 19:09:01
  • Java流程控制语句最全汇总(中篇)

    2023-11-10 23:52:50
  • Android用Canvas绘制贝塞尔曲线

    2022-11-22 00:23:11
  • 在c#中使用servicestackredis操作redis的实例代码

    2022-06-23 14:28:48
  • Android简单实现弹幕效果

    2022-08-12 01:24:08
  • Unity实现10天签到系统

    2022-07-11 23:40:01
  • Android开发技巧之在a标签或TextView控件中单击链接弹出Activity(自定义动作)

    2023-12-26 09:11:39
  • SpringBoot内置tomcat启动原理详解

    2021-11-02 19:32:33
  • Java中的线程同步与ThreadLocal无锁化线程封闭实现

    2023-09-17 04:48:06
  • Unity使用物理引擎实现多旋翼无人机的模拟飞行

    2021-09-25 04:11:40
  • asp之家 软件编程 m.aspxhome.com