多线程综合练习
一、卖电影票
需求
- 一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒。
- 要求:请用多线程模拟卖票过程并打印剩余电影票的数量。
实现
-
自定义卖电影票的线程类
package com.app.demo41_multithreading_test.test1; /* 自定义卖电影票的线程类 */ public class MyThread extends Thread{ // 第一种方式实现多线程,测试类中MyThread会创建多次,所以需要用static修饰ticket变量 // 一共有1000张电影票 static int ticket = 1000; // 重写run方法 @Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据(已到末尾) if (ticket == 0) { break; }else { //4.判断共享数据(未到末尾) // 每次领取的时间为3000毫秒 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // 当每次被领取的时候,电影票总数-1 ticket--; System.out.println(getName() + "在卖电影票,目前还剩下" + ticket + "张电影票~"); } } } } }
-
测试类
package com.app.demo41_multithreading_test.test1; public class Test { public static void main(String[] args) { /* 多线程综合练习:卖电影票 需求: 一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒。 要求:请用多线程模拟卖票过程并打印剩余电影票的数量。 */ // 1.创建两个线程对象:模拟两个售票窗口 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); // 2.给两个线程设置名称 t1.setName("窗口1"); t2.setName("窗口2"); // 3.启动两个线程 t1.start(); t2.start(); } }
-
运行结果(输出语句是随机打印的,只要不是手动停止运行,那就当票数为0时,程序才会停止运行):
窗口1在卖电影票,目前还剩下999张电影票~ 窗口2在卖电影票,目前还剩下998张电影票~ 窗口2在卖电影票,目前还剩下997张电影票~ 窗口1在卖电影票,目前还剩下996张电影票~ 窗口1在卖电影票,目前还剩下995张电影票~ 窗口2在卖电影票,目前还剩下994张电影票~ 窗口2在卖电影票,目前还剩下993张电影票~ 窗口2在卖电影票,目前还剩下992张电影票~ ...... 窗口1在卖电影票,目前还剩下1张电影票~ 窗口1在卖电影票,目前还剩下0张电影票~ Process finished with exit code 0
二、送礼品
需求
- 有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。
- 要求:利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来。
实现
-
自定义送礼品的线程类
package com.app.demo41_multithreading_test.test2; import com.app.demo41_multithreading_test.test1.MyThread; /* 自定义送礼品的线程类 */ public class MyRunnable implements Runnable { // 第二种方式实现多线程,测试类中MyRunnable只会创建1次,所以不需要用static修饰gift变量 //一共有100份礼品 int gift = 100; //重写run方法 @Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据(已到末尾) if (gift < 10) { System.out.println("礼品还剩下" + gift + "个,不再赠送~"); break; }else { //4.判断共享数据(未到末尾) // 送出礼品,礼品总数-1 gift--; System.out.println(Thread.currentThread().getName() + "在赠送礼品,还剩下" + gift + "个~"); } } } } }
-
测试类
package com.app.demo41_multithreading_test.test2; public class Test { public static void main(String[] args) { /* 多线程综合练习:送礼品 需求: 有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。 要求:利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来。 */ //1.创建参数对象 MyRunnable mr = new MyRunnable(); //2.创建两个线程对象 Thread t1 = new Thread(mr, "周杰伦"); Thread t2 = new Thread(mr, "刘亦菲"); //3.启动两个线程 t1.start(); t2.start(); } }
-
运行结果
周杰伦在赠送礼品,还剩下99个~ 周杰伦在赠送礼品,还剩下98个~ 周杰伦在赠送礼品,还剩下97个~ 周杰伦在赠送礼品,还剩下96个~ 周杰伦在赠送礼品,还剩下95个~ 周杰伦在赠送礼品,还剩下94个~ ...... 刘亦菲在赠送礼品,还剩下63个~ 刘亦菲在赠送礼品,还剩下62个~ 刘亦菲在赠送礼品,还剩下61个~ 刘亦菲在赠送礼品,还剩下60个~ 刘亦菲在赠送礼品,还剩下59个~ 刘亦菲在赠送礼品,还剩下58个~ 刘亦菲在赠送礼品,还剩下57个~ 刘亦菲在赠送礼品,还剩下56个~ 刘亦菲在赠送礼品,还剩下55个~ 刘亦菲在赠送礼品,还剩下54个~ ...... 礼品还剩下9个,不再赠送~ 礼品还剩下9个,不再赠送~ Process finished with exit code 0
三、打印奇数数字
需求
- 同时开启两个线程,共同获取1-100之间的所有数字。
- 要求:将输出所有的奇数。
实现
-
自定义打印1~100之间所有奇数的线程类
package com.app.demo41_multithreading_test.test3; import com.app.demo41_multithreading_test.test1.MyThread; /* 自定义打印奇数数字的线程类 */ public class MyRunnable implements Runnable{ //第二种方式实现多线程,测试类中MyRunnable只会创建1次,所以不需要用static修饰number变量 //定义数字1,表示从1开始 int number = 1; //重写run方法 @Override public void run() { //1.循环 while (true) { //2.同步代码块 synchronized (Thread.class) { //3.判断共享数据(已到末尾) if (number > 100) { break; }else { //4.判断共享数据(未到末尾) // 1~100之间的每一个数对2进行求余数,余数为1就是奇数 if (number % 2 == 1) { System.out.println(Thread.currentThread().getName() + "打印数字:" + number); } // 让number自增,表示从1到2、3、4、5...100 number++; } } } } }
-
测试类
package com.app.demo41_multithreading_test.test3; public class Test { public static void main(String[] args) { /* 多线程综合练习:打印奇数数字 需求: 同时开启两个线程,共同获取1-100之间的所有数字。 要求:将输出所有的奇数。 */ //1.创建参数对象 MyRunnable mr = new MyRunnable(); //2.创建两个线程对象 Thread t1 = new Thread(mr, "线程A"); Thread t2 = new Thread(mr, "线程B"); //3.启动两个线程 t1.start(); t2.start(); } }
-
运行结果
线程A打印数字:1 线程A打印数字:3 线程A打印数字:5 线程A打印数字:7 线程A打印数字:9 线程A打印数字:11 线程A打印数字:13 线程A打印数字:15 线程A打印数字:17 线程A打印数字:19 线程A打印数字:21 线程A打印数字:23 线程A打印数字:25 线程A打印数字:27 线程A打印数字:29 线程A打印数字:31 线程A打印数字:33 线程A打印数字:35 线程A打印数字:37 线程A打印数字:39 线程A打印数字:41 线程B打印数字:43 线程B打印数字:45 线程B打印数字:47 线程B打印数字:49 线程B打印数字:51 线程B打印数字:53 线程B打印数字:55 线程B打印数字:57 线程B打印数字:59 线程B打印数字:61 线程B打印数字:63 线程B打印数字:65 线程B打印数字:67 线程B打印数字:69 线程A打印数字:71 线程A打印数字:73 线程A打印数字:75 线程A打印数字:77 线程A打印数字:79 线程A打印数字:81 线程A打印数字:83 线程A打印数字:85 线程A打印数字:87 线程A打印数字:89 线程A打印数字:91 线程A打印数字:93 线程A打印数字:95 线程A打印数字:97 线程A打印数字:99 Process finished with exit code 0
四、抢红包
需求
-
假设:100元,分成3个红包,现在有5个人去抢。
-
要求:红包是共享数据;5个人是5条线程。
-
打印结果如下:
XXX抢到了XXX元 XXX抢到了XXX元 XXX抢到了XXX元 XXX没抢到 XXX没抢到
实现(不考虑保留小数位)
-
自定义抢红包的线程类
package com.app.demo41_multithreading_test.test4; import java.util.ArrayList; import java.util.Random; /* 自定义抢红包的线程类 */ public class MyThread extends Thread { // 共享数据:100元、3个红包 static double money = 100; static int count = 3; // 定义最小红包的金额:0.01元 static final double MIN_MONEY = 0.01; // 重写run方法 @Override public void run() { //1.循环:在当前业务中用不上,因为每个人只能抢一次红包 //2.同步代码块 synchronized (MyThread.class) { //3.判断共享数据(已经到末尾) if (count == 0) { // 3个红包已全部抢完 System.out.println(getName() + "没有抢到红包~"); } else { //4.判断共享数据(没有到末尾) // 定义变量,用于记录抢到的红包金额 double prize = 0; // 判断目前抢的是否为最后一个红包 if (count == 1) { // 是,则直接将剩余的金额给出去 prize = money; } else { // 否,则随机99.98以内的数额给出去 // 创建随机数对象 Random r = new Random(); // 分析:因为如果随机100以内的数额,有可能会直接将100给随机出去了,这样就不符合需求了 // 所以要留两个0.01元做最小金额 // 计算:100 - 2*0.01 == 99.98 double bound = money - (count - 1) * MIN_MONEY; // 随机一个99.98元以内的红包 // 用于存储0.01~99.98内的所有红包金额 ArrayList<Double> list = new ArrayList<>(); for (double i = MIN_MONEY; i <= bound;i+=0.01) { list.add(i); } // 随机一个集合长度内的索引 int index = r.nextInt(list.size()); // 根据这个随机索引,从红包集合list中随机一个红包金额出来 prize = list.get(index); /*// 判断随机的红包金额是否小于最小红包金额0.01 if (prize < MIN_MONEY) { // 小于,则直接将0.00元改为0.01元 prize = MIN_MONEY; }*/ } // 计算总金额剩余多少? // 剩余金额 = 总金额 - 随机红包金额 money = money - prize; // 红包的个数-1 count--; // 输出提示 System.out.println(getName() + "抢到了" + prize + "元"); } } } }
-
测试类
package com.app.demo41_multithreading_test.test4; public class Test { public static void main(String[] args) { /* 多线程综合练习:抢红包 需求: 假设:100元,分成3个红包,现在有5个人去抢。 要求:红包是共享数据;5个人是5条线程。 打印结果如下: XXX抢到了XXX元 XXX抢到了XXX元 XXX抢到了XXX元 XXX没抢到 XXX没抢到 */ // 创建5条线程 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); MyThread t4 = new MyThread(); MyThread t5 = new MyThread(); // 给5条线程设置名称 t1.setName("张飞"); t2.setName("关羽"); t3.setName("赵云"); t4.setName("刘备"); t5.setName("诸葛亮"); // 启动所有线程 t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
-
运行结果
张飞抢到了54.28999999999777元 诸葛亮抢到了27.300000000001468元 关羽抢到了18.410000000000764元 刘备没有抢到红包~ 赵云没有抢到红包~ Process finished with exit code 0
实现(四舍五入后,并保留2位小数)
-
自定义抢红包的线程类
package com.app.demo41_multithreading_test.test4; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Random; /* 自定义抢红包的线程类 */ public class MyThreadPlus extends Thread { // 共享数据:100元、3个红包 static BigDecimal money = BigDecimal.valueOf(100); static int count = 3; // 定义最小红包的金额:0.01元 static final BigDecimal MIN_MONEY = BigDecimal.valueOf(0.01); // 重写run方法 @Override public void run() { //1.循环:在当前业务中用不上,因为每个人只能抢一次红包 //2.同步代码块 synchronized (MyThreadPlus.class) { //3.判断共享数据(已经到末尾) if (count == 0) { // 3个红包已全部抢完 System.out.println(getName() + "没有抢到红包~"); } else { //4.判断共享数据(没有到末尾) // 定义变量,用于记录抢到的红包金额 BigDecimal prize = BigDecimal.valueOf(0.0); // 判断目前抢的是否为最后一个红包 if (count == 1) { // 是,则直接将剩余的金额给出去 prize = money; } else { // 否,则随机99.98以内的数额给出去 // 创建随机数对象 Random r = new Random(); // 分析:因为如果随机100以内的数额,有可能会直接将100给随机出去了,这样就不符合需求了 // 所以要留两个0.01元做最小金额 // 计算:100 - 2*0.01 == 99.98 // subtract(): 减法;multiply(): 乘法; // doubleValue(): 将BigDecimal类型转换成double类型 // BigDecimal.valueOf(): 将double类型转换成BigDecimal类型 double bound = (money.subtract(BigDecimal.valueOf(count - 1).multiply(MIN_MONEY))).doubleValue(); double i = MIN_MONEY.doubleValue(); // 随机一个99.98元以内的红包 // 用于存储i~bound(0.01~99.98)内的所有红包金额 ArrayList<Double> list = new ArrayList<>(); for (double j = i; j <= bound; j+=0.01) { list.add(j); } // 随机一个集合长度内的索引 int index = r.nextInt(list.size()); // 根据这个随机索引,从红包集合list中随机一个红包金额出来 prize = BigDecimal.valueOf(list.get(index)); } // 设置抢到的红包,小数点保留两位小数,四舍五入 prize = prize.setScale(2, RoundingMode.HALF_UP); // 计算总金额剩余多少? // 剩余金额 = 总金额 - 随机红包金额 money = money.subtract(prize); // 红包的个数-1 count--; // 输出提示 System.out.println(getName() + "抢到了" + prize + "元"); } } } }
-
测试类
package com.app.demo41_multithreading_test.test4; public class TestPlus { public static void main(String[] args) { /* 多线程综合练习:抢红包 需求: 假设:100元,分成3个红包,现在有5个人去抢。 要求:红包是共享数据;5个人是5条线程。 打印结果如下: XXX抢到了XXX元 XXX抢到了XXX元 XXX抢到了XXX元 XXX没抢到 XXX没抢到 */ // 创建5条线程 MyThreadPlus t1 = new MyThreadPlus(); MyThreadPlus t2 = new MyThreadPlus(); MyThreadPlus t3 = new MyThreadPlus(); MyThreadPlus t4 = new MyThreadPlus(); MyThreadPlus t5 = new MyThreadPlus(); // 给5条线程设置名称 t1.setName("张飞"); t2.setName("关羽"); t3.setName("赵云"); t4.setName("刘备"); t5.setName("诸葛亮"); // 启动所有线程 t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
-
运行结果
张飞抢到了90.07元 诸葛亮抢到了6.99元 赵云抢到了2.94元 刘备没有抢到红包~ 关羽没有抢到红包~ Process finished with exit code 0
五、抽奖箱抽奖
需求
-
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为{10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700}
-
要求:创建两个抽奖箱(线程),设置线程名称分别为:抽奖箱1、抽奖箱2
-
随机从抽奖池中获取奖项元素并打印出来(每次抽出一个奖项就随机打印一个):
抽奖箱1 又产生了一个10元大奖 抽奖箱1 又产生了一个100元大奖 抽奖箱1 又产生了一个200元大奖 抽奖箱1 又产生了一个800元大奖 抽奖箱2 又产生了一个700元大奖 ......
实现
-
自定义抽奖箱抽奖的线程类
package com.app.demo41_multithreading_test.test5; import java.util.ArrayList; import java.util.Collections; /* 自定义抽奖箱抽奖的线程类 */ public class MyThread extends Thread{ // 共享数据:奖池(用集合比较方便) ArrayList<Integer> list; // 不做初始化,当创建线程对象的时候传进来即可 // 线程类有参构造方法 public MyThread(ArrayList<Integer> list) { this.list = list; } // 重写run方法 @Override public void run() { // 1.循环 while (true) { // 2.同步代码块 synchronized (MyThread.class) { // 3.判断:共享数据已经到末尾 if (list.size() == 0) { // 如果集合中的大小为0,说明所有奖已经全部抽完 break; }else { // 4.判断:共享数据没有到末尾 // 如果集合中的大小不为0,开始抽奖 // 将奖池中的奖金全部打乱顺序 Collections.shuffle(list); // 第一个就是随机的奖金,并将抽到的奖金从奖池中删除 Integer prize = list.remove(0); System.out.println(getName() + " 又产生了一个" + prize + "元大奖~"); } } // 为了能让两个线程平均的抽到奖,适当的让线程睡眠10毫秒 try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
-
测试类
package com.app.demo41_multithreading_test.test5; import java.util.ArrayList; import java.util.Collections; public class Test { public static void main(String[] args) { /* 多线程综合练习:抽奖箱抽奖 需求: 有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为{10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700} 要求:创建两个抽奖箱(线程),设置线程名称分别为:抽奖箱1、抽奖箱2 随机从抽奖池中获取奖项元素并打印出来(每次抽出一个奖项就随机打印一个): 抽奖箱1 又产生了一个10元大奖 抽奖箱1 又产生了一个100元大奖 抽奖箱1 又产生了一个200元大奖 抽奖箱1 又产生了一个800元大奖 抽奖箱2 又产生了一个700元大奖 ... */ // 创建奖池 ArrayList<Integer> list = new ArrayList<>(); // 初始化奖池数据 Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700); // 创建两个线程对象 MyThread t1 = new MyThread(list); MyThread t2 = new MyThread(list); // 给线程对象设置名称 t1.setName("抽奖箱1"); t2.setName("抽奖箱2"); // 启动所有线程对象 t1.start(); t2.start(); } }
-
运行结果
抽奖箱1 又产生了一个5元大奖~ 抽奖箱2 又产生了一个50元大奖~ 抽奖箱1 又产生了一个100元大奖~ 抽奖箱2 又产生了一个800元大奖~ 抽奖箱1 又产生了一个700元大奖~ 抽奖箱2 又产生了一个2元大奖~ 抽奖箱2 又产生了一个20元大奖~ 抽奖箱1 又产生了一个300元大奖~ 抽奖箱2 又产生了一个80元大奖~ 抽奖箱1 又产生了一个10元大奖~ 抽奖箱2 又产生了一个500元大奖~ 抽奖箱1 又产生了一个200元大奖~ Process finished with exit code 0
六、统计并求最大值
需求
在上一个抽奖练习的基础上继续完成如下需求:
-
每次抽奖的过程中,不打印,抽完时一次性打印(随机):
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元。 在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。
-
以上打印效果只是数据模拟,实际代码运行的效果会有差异。
实现(方式1:不推荐)
package com.app.demo41_multithreading_test.test5case1;
import java.util.ArrayList;
import java.util.Collections;
/*
自定义抽奖箱抽奖的线程类
*/
public class MyThread extends Thread{
// 共享数据:奖池(用集合比较方便)
ArrayList<Integer> list; // 不做初始化,当创建线程对象的时候传进来即可
// 线程类有参构造方法
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
// 定义集合,用于存储抽中的奖项
static ArrayList<Integer> prizeList1 = new ArrayList<>();
static ArrayList<Integer> prizeList2 = new ArrayList<>();
// 重写run方法
@Override
public void run() {
// 定义计数器
int count1 = 0;
int count2 = 0;
// 1.循环
while (true) {
// 2.同步代码块
synchronized (MyThread.class) {
// 3.判断:共享数据已经到末尾
if (list.size() == 0) {
// 如果集合中的大小为0,说明所有奖已经全部抽完(抽奖结束)
// 判断是哪个抽奖箱
if ("抽奖箱1".equals(getName())) {
show(getSum(prizeList1), getMax(prizeList1), count1, prizeList1);
}else {
show(getSum(prizeList2), getMax(prizeList2), count2, prizeList2);
}
break;
}else {
// 4.判断:共享数据没有到末尾
// 如果集合中的大小不为0,开始抽奖
// 将奖池中的奖金全部打乱顺序
Collections.shuffle(list);
// 第一个就是随机的奖金,并将抽到的奖金从奖池中删除
int prize = list.remove(0);
// 判断是哪个抽奖箱
if ("抽奖箱1".equals(getName())) {
prizeList1.add(prize);
// 每抽中一个奖项,计数器变量值+1
count1++;
}else {
prizeList2.add(prize);
count2++;
}
}
}
// 为了能让两个线程平均的抽到奖,适当的让线程睡眠10毫秒
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 显示抽奖结果
public void show(int sum, int max, int count, ArrayList<Integer> list) {
// 如果集合中的大小为0,说明所有奖已经全部抽完(抽奖结束)
System.out.print("在此次抽奖过程中," + getName() + "总共产生了" + count + "个奖项,分别为:");
// 遍历奖项集合,用于展示
for (int i = 0; i < list.size(); i++) {
System.out.print(i == list.size() - 1 ? list.get(i) + "最高奖项为" + max + "元,总计额为" + sum + "元。\n" : list.get(i) + ", ");
}
}
// 求最大值
public int getMax(ArrayList<Integer> list) {
// 假设奖项集合中的首元素为最大值
int max = list.get(0);
// 求和、求最大值
for (int prize : list) {
// 依次用max变量中的值 与 每一个奖项进行比较
if (prize > max) {
// 如果当前这个奖项 大于 max变量中的值,则记录当前这个奖项prize为最大值
max = prize;
}
}
return max;
}
// 求和
public int getSum(ArrayList<Integer> list) {
// 定义求和变量
int sum = 0;
// 求和、求最大值
for (int prize : list) {
// 依次将每一个奖项数据进行累加
sum += prize;
}
return sum;
}
}
package com.app.demo41_multithreading_test.test5case1;
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
/*
多线程综合练习:统计并求最大值
需求:
在上一个抽奖练习的基础上继续完成如下需求:
每次抽奖的过程中,不打印,抽完时一次性打印(随机):
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元。
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。
以上打印效果只是数据模拟,实际代码运行的效果会有差异。
*/
// 创建奖池
ArrayList<Integer> list = new ArrayList<>();
// 初始化奖池数据
Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
// 创建两个线程对象
MyThread t1 = new MyThread(list);
MyThread t2 = new MyThread(list);
// 给线程对象设置名称
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
// 启动所有线程对象
t1.start();
t2.start();
}
}
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:700, 80, 800, 100, 10, 300最高奖项为800元,总计额为1990元。
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:2, 20, 50, 5, 500, 200最高奖项为500元,总计额为777元。
Process finished with exit code 0
实现(方式2:推荐)
package com.app.demo41_multithreading_test.test5case2;
import java.util.ArrayList;
import java.util.Collections;
/*
自定义抽奖箱抽奖的线程类
*/
public class MyThread extends Thread {
// 共享数据:奖池(用集合比较方便)
ArrayList<Integer> list; // 不做初始化,当创建线程对象的时候传进来即可
// 线程类有参构造方法
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
// 重写run方法
@Override
public void run() {
// 定义集合,用于存储奖项数据
ArrayList<Integer> prizeList = new ArrayList<>();
// 定义计数器
int count = 0;
// 1.循环
while (true) {
// 2.同步代码块
synchronized (MyThread.class) {
// 3.判断:共享数据已经到末尾
if (list.size() == 0) {
// 如果集合中的大小为0,说明所有奖已经全部抽完(抽奖结束)
show(getSum(prizeList), getMax(prizeList), count, prizeList);
break;
} else {
// 4.判断:共享数据没有到末尾
// 如果集合中的大小不为0,开始抽奖
// 将奖池中的奖金全部打乱顺序
Collections.shuffle(list);
// 第一个就是随机的奖金,并将抽到的奖金从奖池中删除
int prize = list.remove(0);
prizeList.add(prize);
// 每抽中一个奖项,计数器变量值+1
count++;
}
}
// 为了能让两个线程平均的抽到奖,适当的让线程睡眠10毫秒
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 显示抽奖结果
public void show(int sum, int max, int count, ArrayList<Integer> list) {
// 如果集合中的大小为0,说明所有奖已经全部抽完(抽奖结束)
System.out.print("在此次抽奖过程中," + getName() + "总共产生了" + count + "个奖项,分别为:");
// 遍历奖项集合,用于展示
for (int i = 0; i < list.size(); i++) {
System.out.print(i == list.size() - 1 ? list.get(i) + "最高奖项为" + max + "元,总计额为" + sum + "元。\n" : list.get(i) + ", ");
}
}
// 求最大值
public int getMax(ArrayList<Integer> list) {
// 假设奖项集合中的首元素为最大值
int max = list.get(0);
// 求和、求最大值
for (int prize : list) {
// 依次用max变量中的值 与 每一个奖项进行比较
if (prize > max) {
// 如果当前这个奖项 大于 max变量中的值,则记录当前这个奖项prize为最大值
max = prize;
}
}
return max;
}
// 求和
public int getSum(ArrayList<Integer> list) {
// 定义求和变量
int sum = 0;
// 求和、求最大值
for (int prize : list) {
// 依次将每一个奖项数据进行累加
sum += prize;
}
return sum;
}
}
package com.app.demo41_multithreading_test.test5case2;
import java.util.ArrayList;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
/*
多线程综合练习:统计并求最大值
需求:
在上一个抽奖练习的基础上继续完成如下需求:
每次抽奖的过程中,不打印,抽完时一次性打印(随机):
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元。
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。
以上打印效果只是数据模拟,实际代码运行的效果会有差异。
*/
// 创建奖池
ArrayList<Integer> list = new ArrayList<>();
// 初始化奖池数据
Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
// 创建线程对象
MyThread t1 = new MyThread(list);
MyThread t2 = new MyThread(list);
MyThread t3 = new MyThread(list);
// 给线程对象设置名称
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t3.setName("抽奖箱3");
// 启动所有线程对象
t1.start();
t2.start();
t3.start();
}
}
在此次抽奖过程中,抽奖箱2总共产生了3个奖项,分别为:50, 2, 80最高奖项为80元,总计额为132元。
在此次抽奖过程中,抽奖箱3总共产生了4个奖项,分别为:20, 5, 500, 200最高奖项为500元,总计额为725元。
在此次抽奖过程中,抽奖箱1总共产生了5个奖项,分别为:100, 10, 800, 700, 300最高奖项为800元,总计额为1910元。
Process finished with exit code 0
七、多线程之间的比较
需求
在上一个统计并求最大值练习的基础上继续完成如下需求:
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元。
在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。
在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元。
- 以上打印效果只是数据模拟,实际代码运行的效果会有差异。
实现
-
使用第三种方式自定义抽奖箱抽奖的线程类
package com.app.demo41_multithreading_test.test6; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.Callable; /* 使用第三种方式自定义抽奖箱抽奖的线程类 */ public class MyCallable implements Callable<Integer> { // 共享数据:奖池(用集合比较方便) ArrayList<Integer> list; // 不做初始化,当创建线程对象的时候传进来即可 // 线程类有参构造方法 public MyCallable(ArrayList<Integer> list) { this.list = list; } // 显示抽奖结果 public void show(int sum, int max, int count, ArrayList<Integer> list) { // 如果集合中的大小为0,说明所有奖已经全部抽完(抽奖结束) System.out.print("在此次抽奖过程中," + Thread.currentThread().getName() + "总共产生了" + count + "个奖项,分别为:"); // 遍历奖项集合,用于展示 for (int i = 0; i < list.size(); i++) { System.out.print(i == list.size() - 1 ? list.get(i) + "最高奖项为" + max + "元,总计额为" + sum + "元。\n" : list.get(i) + ", "); } } // 求最大值 public int getMax(ArrayList<Integer> list) { // 假设奖项集合中的首元素为最大值 int max = list.get(0); // 求和、求最大值 for (int prize : list) { // 依次用max变量中的值 与 每一个奖项进行比较 if (prize > max) { // 如果当前这个奖项 大于 max变量中的值,则记录当前这个奖项prize为最大值 max = prize; } } return max; } // 求和 public int getSum(ArrayList<Integer> list) { // 定义求和变量 int sum = 0; // 求和、求最大值 for (int prize : list) { // 依次将每一个奖项数据进行累加 sum += prize; } return sum; } // 重写call方法 @Override public Integer call() throws Exception { // 定义集合,用于存储奖项数据 ArrayList<Integer> prizeList = new ArrayList<>(); // 定义计数器 int count = 0; // 1.循环 while (true) { // 2.同步代码块 synchronized (MyCallable.class) { // 3.判断:共享数据已经到末尾 if (list.size() == 0) { // 如果集合中的大小为0,说明所有奖已经全部抽完(抽奖结束) // 展示抽奖箱抽奖结果 show(getSum(prizeList), Collections.max(prizeList), count, prizeList); break; } else { // 4.判断:共享数据没有到末尾 // 如果集合中的大小不为0,开始抽奖 // 将奖池中的奖金全部打乱顺序 Collections.shuffle(list); // 第一个就是随机的奖金,并将抽到的奖金从奖池中删除 int prize = list.remove(0); prizeList.add(prize); // 每抽中一个奖项,计数器变量值+1 count++; } } // 为了能让两个线程平均的抽到奖,适当的让线程睡眠10毫秒 Thread.sleep(10); } // 如果该线程没有抽到奖 if (prizeList.size() == 0) { // 则返回null return null; }else { // 如果线程抽到奖,则返回该线程的最大值 return Collections.max(prizeList); } } }
-
测试类
package com.app.demo41_multithreading_test.test6; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { /* 多线程综合练习:多线程之间的比较 需求: 在上一个统计并求最大值练习的基础上继续完成如下需求: 在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元。 在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。 在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元。 以上打印效果只是数据模拟,实际代码运行的效果会有差异!!! */ // 创建奖池 ArrayList<Integer> list = new ArrayList<>(); // 初始化奖池数据 Collections.addAll(list, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700); // 创建多线程要运行的参数对象 MyCallable mc = new MyCallable(list); // 创建多线程运行结果的管理者对象 FutureTask<Integer> ft1 = new FutureTask<>(mc); FutureTask<Integer> ft2 = new FutureTask<>(mc); // 创建线程对象 Thread t1 = new Thread(ft1); Thread t2 = new Thread(ft2); // 给线程对象设置名称 t1.setName("抽奖箱1"); t2.setName("抽奖箱2"); // 启动所有线程对象 t1.start(); t2.start(); // 获取线程的 Integer max1 = ft1.get(); Integer max2 = ft2.get(); // 线程之间的比较 if (max1 > max2) { System.out.println("在此次抽奖过程中," + t1.getName() + "中产生了最大奖项,该奖项金额为" + max1 + "元。"); }else { System.out.println("在此次抽奖过程中," + t2.getName() + "中产生了最大奖项,该奖项金额为" + max2 + "元。"); } } }
-
运行结果
在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:50, 200, 20, 500, 2, 700最高奖项为700元,总计额为1472元。 在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5, 100, 800, 80, 10, 300最高奖项为800元,总计额为1295元。 在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元。 Process finished with exit code 0