多线程综合练习3

练习5

✅ 设计思路:

  1. 将奖项放入一个数组或列表中。
  2. 创建两个线程,每个线程循环运行(例如持续 10 次),每次从奖项池中随机选择一个奖
  3. 使用 Random 类生成随机索引,取出对应奖项。
  4. 打印输出,格式如题所示。
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 个奖项

✅ 关键点分析:

  1. 不再实时打印 → 需要先收集所有中奖信息,最后统一打印。
  2. 每个线程抽 6 次 → 使用循环控制。
  3. 随机从奖项池中抽取 → 可重复抽取。
  4. 记录每个线程的中奖数据
    • 所有奖项列表(用于显示"分别为")
    • 最大奖项金额
    • 总金额
  5. 线程间共享数据?
    → 不需要,每个线程独立操作自己的奖项列表。
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

✅ 设计思路:

  1. 每个线程独立抽6次,记录自己的奖项。
  2. 抽完后计算:
    • 自己的最大奖项
    • 自己的总金额
  3. 使用 synchronized 控制输出顺序,避免交错。
  4. 所有线程结束后,比较两个线程的最大奖项,找出全局最大值。
  5. 输出谁产生了最大奖项。

⚠️ 注意:由于是随机抽取,不能保证每次都能抽到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+"元");
        }
    }
}
相关推荐
郝学胜-神的一滴2 小时前
封装OpenGL的Shader相关类:从理论到实践
开发语言·c++·程序人生·游戏·图形渲染
步步为营DotNet2 小时前
深度解析.NET中属性(Property)的幕后机制:优化数据访问与封装
java·算法·.net
Swift社区2 小时前
LeetCode 454 - 四数相加 II
java·算法·leetcode
想做后端的小C2 小时前
Java:访问权限
java·开发语言
啃火龙果的兔子2 小时前
java语言基础
java·开发语言·python
我命由我123452 小时前
Python 开发问题:No Python interpreter configured for the project
开发语言·后端·python·学习·pycharm·学习方法·python3.11
禾高网络2 小时前
互联网医院定制|互联网医院|禾高互联网医院搭建
java·大数据·人工智能·小程序
掘根2 小时前
【消息队列项目】消费者管理模块实现
java·开发语言
lzhdim2 小时前
C#应用程序取得当前目录和退出
开发语言·数据库·microsoft·c#