练习5
✅ 设计思路:
- 将奖项放入一个数组或列表中。
- 创建两个线程,每个线程循环运行(例如持续 10 次),每次从奖项池中随机选择一个奖。
- 使用
Random类生成随机索引,取出对应奖项。 - 打印输出,格式如题所示。
java
package com.lkbhua.Test.test4;
import java.util.ArrayList;
import java.util.Collections;
public class MyThread extends Thread {
// 共享数据 (奖励池子)
// 奖励是不能重复的,所以创建一个集合存储比较好
// 但是集合的位置需要好好思索一下,放在成员位置,可能多个线程执行添加的代码的时候会重复添加
// 可以在成员位置定义集合,在下面利用构造方法,在创建本类对象的时候,把集合传递进来。这样就避免了重复添加
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
@Override
public void run() {
// 1、循环
while(true){
synchronized (MyThread.class){
if(list.size() == 0){
break;
}else{
// 继续抽奖
Collections.shuffle(list); // 打乱集合
int prize = list.remove(0);
System.out.println(getName() + "产生了一个"+ prize +" 的奖项" );
}
}
}
}
}
java
package com.lkbhua.Test.test4;
import java.util.ArrayList;
import java.util.Collections;
public class test {
public static void main(String[] args) {
// 创建奖励池子
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("抽奖箱A");
t2.setName("抽奖箱B");
t1.start();
t2.start();
}
}
练习6

🎯 题目要求(在上一题基础上扩展):
在上一题的抽奖系统基础上,新增需求:
- 每次抽的过程不打印(即:不能一边抽一边输出)
- 抽完后一次性打印结果
- 每个抽奖箱要产生 6 个奖项
✅ 关键点分析:
- 不再实时打印 → 需要先收集所有中奖信息,最后统一打印。
- 每个线程抽 6 次 → 使用循环控制。
- 随机从奖项池中抽取 → 可重复抽取。
- 记录每个线程的中奖数据 :
- 所有奖项列表(用于显示"分别为")
- 最大奖项金额
- 总金额
- 线程间共享数据?
→ 不需要,每个线程独立操作自己的奖项列表。
java
package com.lkbhua.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;
}
// 线程1
static ArrayList<Integer> list1 = new ArrayList<>();
// 线程2
static ArrayList<Integer> list2 = new ArrayList<>();
@Override
public void run() {
// 1、循环
while(true){
synchronized (MyThread.class){
if(list.size() == 0){
if("抽奖箱A".equals(getName())){
System.out.println("抽奖箱A中奖的奖品有:" + list1);
}else{
System.out.println("抽奖箱B中奖的奖品有:" + list2);
}
break;
}else{
// 继续抽奖
Collections.shuffle(list); // 打乱集合
int prize = list.remove(0);
if("抽奖箱A".equals(getName())){
list1.add(prize);
}else{
list2.add(prize);
}
}
}
}
// 计算统计信息
int maxPrize = Collections.max(list1);
int totalAmount = list1.stream().mapToInt(Integer::intValue).sum();
// 一次性打印结果(加锁防止输出交错)
synchronized (System.out) {
System.out.println("在此次抽奖过程中," + getName() + "总共产生了6个奖项。");
System.out.print("分别为:" + list1.toString().replaceAll("\\[", "").replaceAll("\\]", ""));
System.out.println(" 最高奖项为" + maxPrize + "元,总计额为" + totalAmount + "元");
}
}
}
java
package com.lkbhua.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}
创建两个奖励箱(线程)设置线程名称分别为:A、B
随机从抽奖池中取出一个金额并且打印在控制台上,格式如下:
每次抽出一个奖励就打印一个(随机)
奖励箱A: 产生了一个10元大奖
奖励箱B: 产生了一个5元大奖
......
*/
// 创建奖励池子
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("抽奖箱A");
t2.setName("抽奖箱B");
t1.start();
t2.start();
}
}
练习7

✅ 设计思路:
- 每个线程独立抽6次,记录自己的奖项。
- 抽完后计算:
- 自己的最大奖项
- 自己的总金额
- 使用
synchronized控制输出顺序,避免交错。 - 所有线程结束后,比较两个线程的最大奖项,找出全局最大值。
- 输出谁产生了最大奖项。
⚠️ 注意:由于是随机抽取,不能保证每次都能抽到800元 ,但可以模拟指定结果 或让代码自动判断。
java
package com.lkbhua.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;
}
@Override
public Integer call() throws Exception {
ArrayList<Integer> boxList = new ArrayList<>();
// 1、循环
while (true) {
synchronized (MyCallable.class) {
if (list.size() == 0) {
System.out.println(Thread.currentThread().getName() + "中奖的奖品有:" + boxList);
break;
} else {
// 继续抽奖
Collections.shuffle(list); // 打乱集合
int prize = list.remove(0);
boxList.add(prize);
}
}
Thread.sleep(100);
}
// 把集合中的最大值返回
if(boxList.size() == 0){
return null;
}else{
return Collections.max(boxList);
}
}
}
java
package com.lkbhua.Test.test6;
import com.lkbhua.Test.test5.MyThread;
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 {
/*
有一个抽奖池,该抽奖池子中存放了奖励的金额,该抽奖池中的奖励为
{10,5,20,50,100,200,500,800,2,80,300,700}
创建两个奖励箱(线程)设置线程名称分别为:A、B
随机从抽奖池中取出一个金额并且打印在控制台上,格式如下:
在此次抽奖过程中,抽将箱A 总共产生了6个奖项,分别为:10,5,20,50,100,200
最高为200,总金额为: 1000
在此次抽奖过程中,抽将箱B 总共产生了6个奖项,分别为:10,5,20,50,800,200
最高为800,总金额为: 1700
在此次抽奖过程中,抽奖箱B中产生了最大奖项,为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);
// 创建线程对象
MyThread t1 = new MyThread(ft1);
MyThread t2 = new MyThread(ft2);
// 设置名字
t1.setName("抽奖箱A");
t2.setName("抽奖箱B");
t1.start();
t2.start();
Integer max1 = ft1.get();
Integer max2 = ft2.get();
System.out.println(max1);
System.out.println(max2);
if (max1 > max2) {
System.out.println("在此次抽奖过程中,最大的为"+max1+"元");
}else {
System.out.println("在此次抽奖过程中,最大的为"+max2+"元");
}
}
}
