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()方法作為運行代碼,而不需要調用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<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多線程實現簡易微信發紅包的文章就介紹到這瞭,更多相關Java多線程實現微信發紅包內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java實例項目零錢通的實現流程
- Java基礎語法:邏輯控制
- Java基礎題新手練習(三)
- Java Scanner的使用和hasNextXXX()的用法說明
- Java中字符序列的替換與分解的幾種實現方法