一、
首先我們先大致了解一下什么是多線程。(書上的解釋)
程序是一段靜態(tài)的代碼,它是應(yīng)用軟件的藍(lán)本。進(jìn)程是程序的一次動(dòng)態(tài)執(zhí)行過程,對(duì)應(yīng)了從代碼加載執(zhí)行,執(zhí)行到執(zhí)行完畢的一個(gè)完整的過程。
線程不是進(jìn)程,線程是比進(jìn)程更小的執(zhí)行單位,一個(gè)進(jìn)程在其執(zhí)行過程中,可以產(chǎn)生多個(gè)線程形成多條執(zhí)行線索,每條線索即每個(gè)線程也有它自身的產(chǎn)生,存在,消亡的過程,和進(jìn)程共享操作系統(tǒng)的資源類似,線程間也可以共享進(jìn)程中的某些內(nèi)存單元,并利用這些共享單元來實(shí)現(xiàn)數(shù)據(jù)交換,實(shí)時(shí)通信與必要的同步操作,但與進(jìn)程不同的是線程的中斷和恢復(fù)更加節(jié)省開支。線程是運(yùn)行在進(jìn)程中的“小進(jìn)程”。
多線程是指一個(gè)應(yīng)用程序中同時(shí)存在幾個(gè)執(zhí)行體,按幾條不同的執(zhí)行線索共同工作的情況。雖然看似是幾個(gè)事件同時(shí)發(fā)生,但其實(shí)計(jì)算機(jī)在任何給定時(shí)刻只能執(zhí)行那些線程中的一個(gè)。為了建立這些線程在同步進(jìn)行的感覺,java虛擬機(jī)快速的把控制從一個(gè)線程切換到另一個(gè)線程。這些線程將被輪流執(zhí)行,使得每個(gè)線程都有機(jī)會(huì)使用cpu資源。
二、
利用單線程實(shí)現(xiàn)的簡(jiǎn)易微信發(fā)紅包
共寫有三種方法,其中第一種,第二種未設(shè)置范圍,紅包數(shù)和人數(shù)為一一對(duì)應(yīng),第三種增添了取值范圍以及計(jì)數(shù)器,人多紅包少有未搶到現(xiàn)象發(fā)生。
(1) 方法一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
import java.util.scanner; import com.sun.deploy.security.selectablesecuritymanager; import java.util.random; public class 簡(jiǎn)易微信發(fā)紅包 { public static void main(string[] args) { scanner scanner= new scanner(system.in); int n; double money; system.out.println( "請(qǐng)輸入您想要發(fā)的紅包數(shù)量" ); n=scanner.nextint(); system.out.println( "請(qǐng)輸入您發(fā)送的紅包金額" ); money=scanner.nextdouble(); t2 t2= new t2(n,money); t2.rob(); } } class t2 { public double remain; //有紅包被領(lǐng)取后的余額 int n; //紅包數(shù)量 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 ) { //因?yàn)樽詈笠粋€(gè)人領(lǐng)取金額為前面人領(lǐng)取紅包后剩下的,所以無需再進(jìn)行隨機(jī) x2 = process(); //取隨機(jī)金額 while (judge(x2) != 1 ) { //判斷取到的隨機(jī)金額是否非法,即無法保證后來每個(gè)紅包領(lǐng)取者領(lǐng)到最低金額0.01 x2 = process(); //若非法則重新取隨機(jī)金額 } remain = remain - x2; //當(dāng)領(lǐng)取成功后余額減去領(lǐng)走的金額 n--; //確保每次判斷人數(shù)為所剩紅包數(shù)減1 system.out.println( "紅包獲得者" + a + "獲得" + x2 + "元" ); //此處默認(rèn)領(lǐng)取者順序?yàn)樯?/code> a++; //控制輸出順序 } else { x2 = remain; //因?yàn)樽詈笠粋€(gè)人領(lǐng)取金額為前面人領(lǐng)取紅包后剩下的,所以無需再進(jìn)行隨機(jī) string str = string.valueof(x2); string str1 = string.format( "%.2f" , x2); x2 = double .parsedouble(str1); system.out.println( "紅包獲得者" + a + "獲得" + x2 + "元" ); n--; //確保每次判斷人數(shù)為所剩紅包數(shù)減1 } } } public int judge( double x){ //判斷函數(shù) if (remain-x>(n- 1 )* 0.01 ){ //確保后來紅包領(lǐng)取者最少能領(lǐng)到最低金額0.01 return 1 ; } else return 0 ; } public double process() { //實(shí)現(xiàn)紅包金額隨機(jī)的函數(shù) double x2; double x1; string str1; random random = new random(); //隨機(jī)數(shù)為取0到1之間的任意double值 x1 = remain*random.nextdouble(); str1= string.format( "%.2f" ,x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x2= double .parsedouble(str1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 while (x2== 0 ){ //如果所取金額非法則回爐重造 x1 = remain*random.nextdouble(); str1= string.format( "%.2f" ,x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x2= double .parsedouble(str1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 } return x2; } } |
程序運(yùn)行結(jié)果如下
(2) 方法二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import java.util.random; import java.util.scanner; public class 簡(jiǎn)易微信發(fā)紅包 2 { public static void main(string[] args) { scanner scanner= new scanner(system.in); double money= 0 ; //紅包總金額 int n; //紅包個(gè)數(shù) system.out.println( "請(qǐng)輸入您想要發(fā)的紅包數(shù)量" ); n=scanner.nextint(); system.out.println( "請(qǐng)輸入您發(fā)送的紅包金額" ); money=scanner.nextdouble(); if (money/n== 0.01 ){ //當(dāng)所發(fā)金額剛好為每人0.01元時(shí) 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; //最大可領(lǐng)紅包金額 double x1; //隨機(jī)金額 double x2; //所得金額 while (n> 0 ) { if (n != 1 ) { //前n-1個(gè)紅包領(lǐng)取者領(lǐng)的紅包為隨機(jī)金額紅包 max = remain - (n - 1 ) * 0.01 ; //最大可領(lǐng)紅包金額為剩下的人都獲得最小金額0.01 random random = new random(); x1 = ( double ) random.nextint(( int ) ((max - 0.01 ) * 100 )); //用nextint而不用nextdouble的原因是nextdouble無法設(shè)置seed //上式中max-0.01,下面的x2+0.01即解決了隨機(jī)數(shù)取0導(dǎo)致紅包獲得者沒搶到錢的問題 x1 /= 100.0 ; x2 = x1 + 0.01 ; remain = remain - x2; n--; system.out.println( "紅包獲得者" + a + "獲取金額為:" + string.format( "%.2f" , x2) + "元" ); a++; } else { //最后一人領(lǐng)的紅包為前n-1個(gè)人領(lǐng)完后剩下的紅包 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元" ); } } } |
程序運(yùn)行結(jié)果如下:
(3) 方法三
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
import java.util.random; import java.util.scanner; public class 簡(jiǎn)易微信發(fā)紅包 3 { public static void main(string[] args) { int p,n; double money; system.out.println( "請(qǐng)輸入您發(fā)送的紅包金額" ); scanner scanner= new scanner(system.in); money=scanner.nextdouble(); system.out.println( "請(qǐng)輸入您發(fā)送的紅包數(shù)量" ); n=scanner.nextint(); system.out.println( "請(qǐng)輸入?yún)⑴c搶紅包的人數(shù)" ); p=scanner.nextint(); t7 t7= new t7(money,n,p); t7.rob(); } } class t7 { double money; int n,p; int count = 0 ; //計(jì)數(shù)器 double remain; t7( double money, int n, int p){ this .money=money; //總金額 this .n=n; //紅包數(shù) this .p=p; //搶紅包人數(shù) 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 ); //設(shè)置范圍讓每次所得金額不超過總數(shù)的1/(n-1),這樣也就避免了一次取得過大導(dǎo)致后面搶的紅包不能保證每個(gè)最少0.01 x1 = d * random.nextdouble(); s1 = string.format( "%.2f" , x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x1 = double .parsedouble(s1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 while (x1 == 0 || x1 == money / (n - 1 )) { x1 = d * random.nextdouble(); s1 = string.format( "%.2f" , x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x1 = double .parsedouble(s1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 } s2 = string.format( "%.2f" , remain); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 remain = double .parsedouble(s2); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 if (count < n - 1 ) { //前n-1個(gè)紅包金額為隨機(jī)金額 system.out.println( "紅包搶奪者" +i+ "搶到了" + s1 + "元" ); remain -= x1; count++; } else if (count == n - 1 ) { //第n個(gè)為前n-1個(gè)紅包搶完所剩金額 system.out.println( "紅包搶奪者" +i+ "搶到了" + s2 + "元" ); count++; } else if (count > n - 1 ) { //紅包被搶完后再來的 system.out.println( "紅包搶奪者" +i+ "哎呀,手慢了!沒搶到!" ); count++; } } } } |
程序運(yùn)行結(jié)果如下:
三、
利用多線程實(shí)現(xiàn)的簡(jiǎn)易微信發(fā)紅包
那么如何創(chuàng)建多線程呢?
1.通過繼承thread類創(chuàng)建多線程
jdk中提供了一個(gè)線程類thread,通過繼承thread類,并重寫thread類中的run()方法便可實(shí)現(xiàn)多線程。
在thread類中,提供了一個(gè)start()方法用于啟動(dòng)新線程,線程啟動(dòng)后,系統(tǒng)會(huì)自動(dòng)調(diào)用run()方法,如果子類重寫了該方法便會(huì)執(zhí)行子類中的方法。
run()方法中就是寫能夠被線程執(zhí)行的程序。如果直接調(diào)用則相當(dāng)于普通方法,必須使用start()方法,才能啟動(dòng)線程,然后再由jvm去調(diào)用該線程的run()方法。
創(chuàng)建并啟動(dòng)多線程的步驟
①定義thread類的子類,并重寫該類的run方法,其方法體代表線程需要完成的任務(wù)。因此常把run方法稱為線程執(zhí)行體。
②創(chuàng)建thread子類的實(shí)例,即創(chuàng)建線程對(duì)象。
③用線程對(duì)象的start方法來啟動(dòng)該線程。
2.通過實(shí)現(xiàn)runnable接口創(chuàng)建多線程
通過繼承thread類實(shí)現(xiàn)了多線程,但是這種方式有一定的局限性。因?yàn)閖ava中只支持單繼承,一個(gè)類一旦繼承了某個(gè)父類就無法再繼承thread類。
thread類提供了另外一個(gè)構(gòu)造方法thread(runnable target),其中runnable是一個(gè)接口,它只有一個(gè)run()方法。
當(dāng)通過thread(runnable target))構(gòu)造方法創(chuàng)建線程對(duì)象時(shí),只需為該方法傳遞一個(gè)實(shí)現(xiàn)了runnable接口的實(shí)例對(duì)象,這樣創(chuàng)建的線程將調(diào)用實(shí)現(xiàn)了runnable接口中的run()方法作為運(yùn)行代碼,而不需要調(diào)用thread類中的run()方法。
創(chuàng)建并啟動(dòng)多線程的步驟
①定義runnable接口的實(shí)現(xiàn)類,并重寫該接口的run方法,該run方法的方法體同樣是該線程的線程執(zhí)行體。
②創(chuàng)建runnable實(shí)現(xiàn)類的實(shí)例,并以此為實(shí)例作為thread的參數(shù)來創(chuàng)建thread對(duì)象,該thread對(duì)象才是真正的線程對(duì)象。
當(dāng)多個(gè)線程使用同一個(gè)共享資源時(shí),可以將處理共享資源的代碼放置在一個(gè)代碼塊中,使用synchronized關(guān)鍵字來修飾,被稱作同步代碼塊:
sychronized(lock){
操作共享資源代碼塊
}
其中:lock是一個(gè)鎖對(duì)象,它是同步代碼塊的關(guān)鍵。當(dāng)線程執(zhí)行同步代碼塊時(shí),首先會(huì)檢查鎖對(duì)象的標(biāo)志位,默認(rèn)情況下,標(biāo)志位為1,此時(shí)線程會(huì)執(zhí)行同步代碼塊,同時(shí)將鎖對(duì)象的標(biāo)志位置為0。當(dāng)一個(gè)新的線程執(zhí)行到這段同步代碼塊時(shí),由于鎖對(duì)象的標(biāo)志位為0,新線程會(huì)發(fā)生阻塞,等待當(dāng)前線程執(zhí)行完同步代碼塊后,鎖對(duì)象的標(biāo)志位被置為1,新線程才能進(jìn)入同步代碼塊執(zhí)行其中的代碼。循環(huán)往復(fù),直到共享資源被處理完為止。
同步代碼塊可以有效解決線程的安全問題,當(dāng)把共享資源的操作放在synchronized定義的區(qū)域內(nèi)時(shí),便為這些操作加了同步鎖。
在方法前面同樣可以使用synchronized關(guān)鍵字來修飾,被修飾的方法為同步方法,它能實(shí)現(xiàn)和同步代碼塊同樣的功能,具體語(yǔ)法格式如下:
synchronized 返回值類型 方法名 {}
被synchronized修飾的方法在某一時(shí)刻只允許一個(gè)線程訪問,訪問該方法的其它線程都會(huì)發(fā)生阻塞,直到當(dāng)前線程訪問完畢后,其它線程才有機(jī)會(huì)執(zhí)行方法。
另外
public final string getname():獲取線程的名稱。
public static thread currentthread():返回當(dāng)前正在執(zhí)行的線程對(duì)象,這樣就可以獲取任意方法所在的線程名稱。
thread.currentthread().getname()
現(xiàn)將上面的單線程改成多線程實(shí)現(xiàn)
本篇文章多線程的創(chuàng)建以及實(shí)現(xiàn)用runnable接口實(shí)現(xiàn)
(1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
import java.util.scanner; import com.sun.deploy.security.selectablesecuritymanager; import java.util.random; public class 微信發(fā)紅包多線程 { public static void main(string[] args) { scanner scanner= new scanner(system.in); int n; double money; system.out.println( "請(qǐng)輸入您想要發(fā)的紅包數(shù)量" ); n=scanner.nextint(); system.out.println( "請(qǐng)輸入您發(fā)送的紅包金額" ); money=scanner.nextdouble(); t3 t3= new t3(n,money); //創(chuàng)建runnable實(shí)現(xiàn)類的實(shí)例 for ( int j = 1 ; j <= n; j++) { new thread(t3, "紅包獲得者" + j).start(); //以上面創(chuàng)建的實(shí)例作為thread的參數(shù)來創(chuàng)建thread對(duì)象,并為thread對(duì)象指定一個(gè)名字,用線程對(duì)象的start方法來啟動(dòng)該線程。 } } } class t3 implements runnable { //實(shí)現(xiàn)runnable接口 public double remain; //有紅包被領(lǐng)取后的余額 int n; //紅包數(shù)量 public synchronized void run() { //同步方法,在某一時(shí)刻只允許一個(gè)線程訪問,防止數(shù)據(jù)錯(cuò)亂 rob(); } t3( int n, double money) { this .remain = money; this .n = n; } int a = n; public void rob() { double x2; if (n != 1 ) { //因?yàn)樽詈笠粋€(gè)人領(lǐng)取金額為前面人領(lǐng)取紅包后剩下的,所以無需再進(jìn)行隨機(jī) x2 = process(); //取隨機(jī)金額 while (judge(x2) != 1 ) { //判斷取到的隨機(jī)金額是否非法,即是否能保證后來每個(gè)紅包領(lǐng)取者領(lǐng)到最低金額0.01 x2 = process(); //若非法則重新取隨機(jī)金額 } remain = remain - x2; //當(dāng)領(lǐng)取成功后余額減去領(lǐng)走的金額 n--; //確保每次判斷人數(shù)為紅包數(shù)減一 } else { x2 = remain; //因?yàn)樽詈笠粋€(gè)人領(lǐng)取金額為前面人領(lǐng)取紅包后剩下的,所以無需再進(jìn)行隨機(jī) string str = string.valueof(x2); string str1 = string.format( "%.2f" , x2); x2 = double .parsedouble(str1); } thread th = thread.currentthread(); //返回當(dāng)前正在執(zhí)行的線程對(duì)象 string th_name = th.getname(); //獲取線程的名稱 system.out.println(th_name + "搶到" + x2 + "元" ); } public int judge( double x) { //判斷函數(shù) if (remain - x > (n - 1 ) * 0.01 ) { //確保后來紅包領(lǐng)取者能領(lǐng)到最低金額0.01 return 1 ; } else return 0 ; } public double process() { //實(shí)現(xiàn)紅包金額隨機(jī)的函數(shù) double x2; double x1; string str1; random random = new random(); //隨機(jī)數(shù)為取0到1之間的任意double值 x1 = remain * random.nextdouble(); str1 = string.format( "%.2f" , x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x2 = double .parsedouble(str1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 while (x2 == 0 ) { //如果所取金額非法則回爐重造 x1 = remain * random.nextdouble(); str1 = string.format( "%.2f" , x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x2 = double .parsedouble(str1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 } return x2; } } |
程序運(yùn)行結(jié)果如下:
(2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import java.util.random; import java.util.scanner; public class 簡(jiǎn)易微信發(fā)紅包多線程 2 { public static void main(string[] args) { scanner scanner= new scanner(system.in); double money= 0 ; //紅包總金額 int n; //紅包個(gè)數(shù) system.out.println( "請(qǐng)輸入您想要發(fā)的紅包數(shù)量" ); n=scanner.nextint(); system.out.println( "請(qǐng)輸入您發(fā)送的紅包金額" ); money=scanner.nextdouble(); if (money/n== 0.01 ){ //當(dāng)所發(fā)金額剛好為每人0.01元時(shí) 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; //最大可領(lǐng)紅包金額 double x1; //隨機(jī)金額 double x2; //所得金額 if (n!= 1 ) { //前n-1個(gè)紅包領(lǐng)取者領(lǐng)的紅包為隨機(jī)金額紅包 max=remain-(n- 1 )* 0.01 ; //最大可領(lǐng)紅包金額為剩下的人都獲得最小金額0.01 random random= new random(); x1=( double )random.nextint(( int ) ((max- 0.01 )* 100 )); //用nextint而不用nextdouble的原因是nextdouble無法設(shè)置seed //上式中max-0.01,下面的x2+0.01即解決了隨機(jī)數(shù)取0導(dǎo)致紅包獲得者沒搶到錢的問題 x1/= 100.0 ; x2=x1+ 0.01 ; remain=remain-x2; n=n- 1 ; thread th=thread.currentthread(); //獲取當(dāng)前線程 string th_name=th.getname(); //獲取線程名字 system.out.println(th_name+ "獲取金額為:" +string.format( "%.2f" , x2)+ "元" ); } else { //最后一人領(lǐng)的紅包為前n-1個(gè)人領(lǐng)完后剩下的紅包 thread th=thread.currentthread(); //獲取當(dāng)前線程 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(); //獲取當(dāng)前線程 string th_name=th.getname(); //獲取線程名字 system.out.println(th_name+ "獲取金額為:" +string.format( "%.2f" , remain/n)+ "元" ); } } |
程序運(yùn)行結(jié)果如下:
(3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
import java.util.random; import java.util.scanner; public class 簡(jiǎn)易微信發(fā)紅包多線程 3 { public static void main(string[] args) { int p,n; double money; system.out.println( "請(qǐng)輸入您發(fā)送的紅包金額" ); scanner scanner= new scanner(system.in); money=scanner.nextdouble(); system.out.println( "請(qǐng)輸入您發(fā)送的紅包數(shù)量" ); n=scanner.nextint(); system.out.println( "請(qǐng)輸入?yún)⑴c搶紅包的人數(shù)" ); p=scanner.nextint(); hh hh= new hh(money,n); for ( int i= 1 ;i<=p;i++){ new thread(hh, "第" +i+ "個(gè)人" ).start(); } } } class hh implements runnable{ double money; int n; int count = 0 ; //計(jì)數(shù)器 double remain; hh( double money, int n){ this .money=money; //總金額 this .n=n; //紅包數(shù) this .remain=money; //所剩金額 } @override public synchronized void run() { rob(); } public void rob(){ double x1,x2,d; string s1,s2; thread th=thread.currentthread(); //獲取當(dāng)前線程 string th_name=th.getname(); //獲取線程名字 random random= new random(); d=money/(n- 1 ); //設(shè)置范圍讓每次所得金額不超過總數(shù)的1/(n-1),這樣也就避免了一次取得過大導(dǎo)致后面搶的紅包不能保證每個(gè)最少0.01 x1=d*random.nextdouble(); s1=string.format( "%.2f" ,x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x1 = double .parsedouble(s1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 while (x1== 0 ||x1==money/(n- 1 )){ x1=d*random.nextdouble(); s1=string.format( "%.2f" ,x1); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 x1 = double .parsedouble(s1); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 } s2= string.format( "%.2f" ,remain); //轉(zhuǎn)化成字符串型用字符串型的format進(jìn)行格式化處理,紅包金額最多取到小數(shù)點(diǎn)后兩位 remain = double .parsedouble(s2); //再將字符串型數(shù)據(jù)轉(zhuǎn)換成double型 if (count<n- 1 ){ //前n-1個(gè)紅包金額為隨機(jī)金額 system.out.println(th_name+ "搶到了" +s1+ "元" ); remain-=x1; count++; } else if (count==n- 1 ){ //第n個(gè)為前n-1個(gè)紅包搶完所剩金額 system.out.println(th_name+ "搶到了" +s2+ "元" ); count++; } else if (count>n- 1 ){ //紅包被搶完后再來的 system.out.println(th_name+ "哎呀,手慢了!沒搶到!" ); count++; } } } |
程序運(yùn)行結(jié)果如下:
總結(jié)
新手上路,因能力有限,若有不足之處還望大家海涵!
到此這篇關(guān)于java多線程實(shí)現(xiàn)簡(jiǎn)易微信發(fā)紅包的文章就介紹到這了,更多相關(guān)java多線程實(shí)現(xiàn)微信發(fā)紅包內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/weixin_46569912/article/details/113308600