首页 > 编程语言 >Java多线程​(五)练习题7道

Java多线程​(五)练习题7道

时间:2023-12-26 13:32:46浏览次数:57  
标签:练习题 抽奖 Java Thread lotteryPool 线程 new 多线程 public

练习

多线程练习1(卖电影票)

一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,要求:请用多线程模拟卖票过程并打印剩余电影票的数量

线程类实现:

public class TicketWindow extends Thread{
 public TicketWindow(){}

 public TicketWindow(String name){
 super(name);
 }
 // 电影票数量
 static int ticketAmount = 1000;

 // 锁对象
 static Object lock = new Object();

 @Override
 public void run() {
 while (true) {
 //synchronized (TicketWindow.class){
 synchronized (lock){
 // 如果票已卖完
 if(ticketAmount == 0){
 break;
 }else {
 // 如果票没卖完
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }

 ticketAmount--;
 System.out.println(getName() + "卖出一张票,还剩" + ticketAmount + "张票。");

 }
 }
 }
 }
}

线程使用类:

public class TheaterSales {
 public static void main(String[] args) {
 // 创建线程对象
 TicketWindow tw1 = new TicketWindow("窗口1");
 TicketWindow tw2 = new TicketWindow("窗口2");

 // 启动线程
 tw1.start();
 tw2.start();
 }
}



多线程练习2(送礼品)(学生自己练习)

有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来。

线程代码:

public class GiftGiver implements Runnable{
 static int pieces = 1000;

 @Override
 public void run() {
 for (;;){
 synchronized (GiftGiver.class) {
 // 小于10份,则退出
 if (pieces < 10){
 break;
 }else {
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 pieces--;
 System.out.println(Thread.currentThread().getName() + "正在送礼物,还剩" + pieces + "份礼物");
 }
 }
 }
 }
}

代码调用:

public class GiftManiplate {
 public static void main(String[] args) {
 // 创建任务器
 GiftGiver gg1 = new GiftGiver();
 GiftGiver gg2 = new GiftGiver();
 // 创建线程对象
 Thread t1 = new Thread(gg1);
 Thread t2 = new Thread(gg2);
 // 命名线程
 t1.setName("丁丁");
 t2.setName("冬冬");
 // 启动线程
 t1.start();
 t2.start();

 }
}



多线程练习3(打印奇数数字)(学生自己练习)

同时开启两个线程,共同获取1-100之间的所有数字。

要求:将输出所有的奇数。

线程实现类:

import java.util.Random;

public class PrimeNumberThread extends Thread{
 // 表示数据的范围
 static int range = 1000;

 @Override
 public void run() {
 for (;;){
 synchronized (PrimeNumberThread.class) {
 // 结束条件达到
 if (range < 1){
 break;
 }else {
 // 未达到结束条件
 try {
 // 随机睡眠0~100毫秒
 Thread.sleep(new Random().nextInt(100));
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 if (range % 2 == 1){
 System.out.println(getName() + ": " + range);
 }
 range--;
 }
 }
 }
 }
}

线程使用:

public class PrimeManiplulate {
 public static void main(String[] args) {
 // 创建线程对象
 PrimeNumberThread t1 = new PrimeNumberThread();
 PrimeNumberThread t2 = new PrimeNumberThread();
 // 启动线程
 t1.start();
 t2.start();
 }
}


多线程练习4(抢红包)

抢红包也用到了多线程。

假设:100块,分成了3个包,现在有5个人去抢。其中,红包是共享数据。5个人是5条线程。

打印结果如下:

XXX抢到了XXX元

XXX抢到了XXX元

XXX抢到了XXX元

XXX没抢到

XXX没抢到

import java.util.Random;

public class HongbaoThread extends Thread{
 // 抽奖总金额
 static double totalAmount = 100;
 // 红包个数
 static int count = 3;
 // 最小红包金额
 static final double MIN = 0.01;

 @Override
 public void run() {
 // 循环, 因为只抢3次,因此不需要循环
 synchronized (HongbaoThread.class) {
 // 同步块

 // 结束条件达到
 if (count == 0){
 System.out.println(getName() + "没抢到!");
 }else {
 // 结束条件未达到
 double prize = 0; // 表示单次抢到的金额
 if (count == 1){
 // 剩下的数额都拿走
 prize = totalAmount;
 }else {
 // 表示第一次、第二次(随机)
 double bounds = totalAmount - (count - 1) * MIN;
 prize = new Random().nextDouble(bounds); // 本次中奖金额
 if (prize < MIN){ // 如果prize过小,则等于最小值
 prize = MIN;
 }
 }
 System.out.println(getName() + "抢到了" + prize + "元");
 totalAmount -= prize;
 count--;
 }
 }
 }
}

使用线程:

public class Test {
 public static void main(String[] args) {
 // 初始化线程对象
 HongbaoThread t1 = new HongbaoThread();
 HongbaoThread t2 = new HongbaoThread();
 HongbaoThread t3 = new HongbaoThread();
 HongbaoThread t4 = new HongbaoThread();
 HongbaoThread t5 = new HongbaoThread();
 // 命名进程
 t1.setName("丁丁");
 t2.setName("冬冬");
 t3.setName("韩梅梅");
 t4.setName("李雷");
 t5.setName("小明");
 // 启动线程
 t1.start();
 t2.start();
 t3.start();
 t4.start();
 t5.start();
 }
}


多线程练习5(抽奖箱抽奖)

有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为

{10,5,20,50,100,200,500,800,2,80,300,700};

创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:

每次抽出一个奖项就打印一个(随机)

抽奖箱1又产生了一个10元大奖

抽奖箱1又产生了一个100元大奖

抽奖箱1又产生了一个200元大奖

抽奖箱1又产生了一个800元大奖

抽奖箱2又产生了一个700元大奖

...

线程实现类:

import java.util.*;

public class HappyLottery extends Thread {
 // 奖池实现方法一
 // 抽奖池,共享一个
 
 static ArrayList<Integer> lotteryPool = new ArrayList<>();

 static {
 // 奖池中添加元素
 Collections.addAll(lotteryPool, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
 }



 // 奖池实现方法二
 // 在初始化本类时,传入一个ArrayList<Integer>对象
 /*
 ArrayList<Integer> lotteryPool;
 public HappyLottery(ArrayList<Integer> lotteryPool){
 this.lotteryPool = lotteryPool;
 }
 */


 // 新线程
 @Override
 public void run() {
 while (true) {
 try {
 Thread.sleep(100); // 线程运行太快,为了让其他线程也能抢到执行权
 } catch (InterruptedException e) {
 throw new RuntimeException(e);
 }
 synchronized (HappyLottery.class) { // 同步代码块
 if (!lotteryPool.isEmpty()) { // 非空
 // 抽出的奖项
 Integer drawed = lotteryPool.remove(new Random().nextInt(lotteryPool.size()));
 System.out.println(getName() + "又产生了一个" + drawed + "元大奖");
 } else { // 空了
 break;
 }
 }
 }
 }
}

线程使用类:

public class HappyLotteryTest {
 public static void main(String[] args) {
 // 初始化线程对象
 HappyLottery h1 = new HappyLottery();
 HappyLottery h2 = new HappyLottery();
 HappyLottery h3 = new HappyLottery();
 // 抽奖箱命名
 h1.setName("抽奖箱1");
 h2.setName("抽奖箱2");
 h3.setName("抽奖箱3");
 // 启动抽奖箱线程
 h1.start();
 h2.start();
 h3.start();
 }
}


多线程练习6(多线程统计并求最大值)

在上一题基础上继续完成如下需求:

每次抽的过程中,不打印,抽完时一次性打印(随机)

在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300最高奖项为300元,总计额为932元。

在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700最高奖项为800元,总计额为1835元。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class HappyLottery extends Thread {
 // 奖池实现方法一
 // 抽奖池,共享一个
 static ArrayList<Integer> lotteryPool = new ArrayList<>();

 // 本线程抽到的奖项
 ArrayList<Integer> thisDraws;

 public HappyLottery(){
 thisDraws = new ArrayList<>(); // 初始化
 }

 static {
 // 奖池中添加元素
 Collections.addAll(lotteryPool, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
 }

 // 奖池实现方法二
 // 在初始化本类时,传入一个ArrayList<Integer>对象
 /*
 ArrayList<Integer> lotteryPool;
 public HappyLottery(ArrayList<Integer> lotteryPool){
 this.lotteryPool = lotteryPool;
 }
 */

 // 新线程
 @Override
 public void run() {
 while (true) {
 synchronized (HappyLottery.class) { // 同步代码块
 if (!lotteryPool.isEmpty()) { // 非空
 // 抽出的奖项
 Integer drawed = lotteryPool.remove(new Random().nextInt(lotteryPool.size()));
 thisDraws.add(drawed);
 //System.out.println(getName() + "又产生了一个" + drawed + "元大奖");
 } else { // 空了
 System.out.println("在此次抽奖过程中," + getName() + "总共产生了" + thisDraws.size() + "个奖项,分别为:");
 System.out.print(thisDraws);
 int sum = 0;
 for (Integer thisDraw : thisDraws) {
 sum += thisDraw;
 }
 System.out.println(",最高奖项为" + Collections.max(thisDraws) + "元," + "总计金额为" + sum + "元");
 break;
 }
 }
 }
 }
}

线程使用:

public class HappyLotteryTest {
 public static void main(String[] args) {
 // 初始化线程对象
 HappyLottery h1 = new HappyLottery();
 HappyLottery h2 = new HappyLottery();
 HappyLottery h3 = new HappyLottery();
 // 抽奖箱命名
 h1.setName("抽奖箱1");
 h2.setName("抽奖箱2");
 h3.setName("抽奖箱3");
 // 启动抽奖箱线程
 h1.start();
 h2.start();
 h3.start();
 }
}


多线程练习7(多线程之间的比较)

在上一题基础上继续完成如下需求:

在此次抽奖过程中,抽奖箱1总共产生了6个奖项,分别为:10,20,100,500,2,300

最高奖项为300元,总计额为932元

在此次抽奖过程中,抽奖箱2总共产生了6个奖项,分别为:5,50,200,800,80,700

最高奖项为800元,总计额为1835元

在此次抽奖过程中,抽奖箱2中产生了最大奖项,该奖项金额为800元

以上打印效果只是数据模拟,实际代码运行的效果会有差异

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.Callable;

public class LotteryBox implements Callable<Integer> {
 // 奖池实现方法一
 // 抽奖池,共享一个
 static ArrayList<Integer> lotteryPool = new ArrayList<>();

 // 本线程抽到的奖项
 ArrayList<Integer> thisDraws;

 public LotteryBox(){
 thisDraws = new ArrayList<>(); // 初始化
 }

 static {
 // 奖池中添加元素
 Collections.addAll(lotteryPool, 10, 5, 20, 50, 100, 200, 500, 800, 2, 80, 300, 700);
 }

 @Override
 public Integer call() throws Exception {
 while (true) {
 synchronized (LotteryBox.class) { // 同步代码块
 if (!lotteryPool.isEmpty()) { // 非空
 // 抽出的奖项
 Integer drawed = lotteryPool.remove(new Random().nextInt(lotteryPool.size()));
 thisDraws.add(drawed);
 //System.out.println(getName() + "又产生了一个" + drawed + "元大奖");
 } else { // 空了
 if (!thisDraws.isEmpty()) {
 System.out.println("在此次抽奖过程中," + Thread.currentThread().getName() + "总共产生了" + thisDraws.size() + "个奖项,分别为:");
 System.out.print(thisDraws);
 int sum = 0;
 for (Integer thisDraw : thisDraws) {
 sum += thisDraw;
 }
 System.out.println(",最高奖项为" + Collections.max(thisDraws) + "元," + "总计金额为" + sum + "元");
 }else {
 System.out.println("在此次抽奖过程中," + Thread.currentThread().getName() + "没有抽到奖。");
 }
 break;
 }
 }
 }
 // 返回值
 if (thisDraws.isEmpty()){
 return 0;
 }else {
 return Collections.max(thisDraws); // 返回本线程抽奖的最大奖额
 }
 }
}

线程使用类:

import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class LotteryBoxRun {
 public static void main(String[] args) throws ExecutionException, InterruptedException {
 // 1。初始化线程类
 LotteryBox b1 = new LotteryBox();
 LotteryBox b2 = new LotteryBox();
 LotteryBox b3 = new LotteryBox();
 // 2。初始化FutureTask对象
 FutureTask<Integer> f1 = new FutureTask<>(b1);
 FutureTask<Integer> f2 = new FutureTask<>(b2);
 FutureTask<Integer> f3 = new FutureTask<>(b3);
 // 3。创建线程对象
 Thread t1 = new Thread(f1);
 Thread t2 = new Thread(f2);
 Thread t3 = new Thread(f3);
 // 命名线程
 t1.setName("抽奖箱1");
 t2.setName("抽奖箱2");
 t3.setName("抽奖箱3");
 // 4。启动线程
 t1.start();
 t2.start();
 t3.start();
 // 5。获取运行结果
 ArrayList<Integer> result = new ArrayList<>();
 Integer r1 = f1.get();
 Integer r2 = f2.get();
 Integer r3 = f3.get();
 result.add(r1);
 result.add(r2);
 result.add(r3);
 // 6。
 Integer max = Collections.max(result);
 int i = result.indexOf(max); // 第几个线程
 System.out.println("在此次抽奖过程中,抽奖箱" + (i + 1) + "中产生了最大奖项,该奖项金额为" + max + "元");
 }
}


标签:练习题,抽奖,Java,Thread,lotteryPool,线程,new,多线程,public
From: https://blog.51cto.com/tangxiaohu/8982039

相关文章

  • Java与线程
    实现线程的主要方式:1) 使用内核实现(1:1实现,JDK线程模型采用方式)内核线程(KLT)就是直接由操作系统内核支持的线程,由内核完成线程切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上.程序一般使用内核线程的一种高级接口-轻量级进程(LWP),由于每个轻......
  • 在 Python 中,​​?:​​​ 符号并不是一个有效的运算符。这个符号在其他一些编程语言
    在Python中,?:符号并不是一个有效的运算符。这个符号在其他一些编程语言中,如JavaScript或C,被称为条件(三元)运算符。然而,在Python中,我们使用if-else表达式来达到相同的目的。例如:x=10y=20print("xisgreater")ifx>yelseprint("yisgreater")在上述代码中,如果......
  • 基于JAVA的汽车售票系统网站
    互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对汽车售票信息管理混乱,出错率高,信息安全性差,劳动强度大,费时费力等问题,采用汽车售票网站可以有效管理,使信息管理能够更加......
  • Java多线程:锁机制深入剖析
    在并发编程中,正确地管理资源的访问至关重要。Java提供了多种锁机制来协调多个线程之间对共享资源的访问。本文将深入探讨Java多线程中的锁机制,包括内置锁(synchronized关键字)、显式锁(java.util.concurrent.locks.Lock)以及并发集合(java.util.concurrent)提供的锁机制。1.内置锁(Synchr......
  • JavaWeb - Day11 - 案例 - 员工管理、文件上传、修改员工、配置文件
    01.案例-员工管理-新增员工前面我们已经实现了员工信息的条件分页查询以及删除操作。关于员工管理的功能,还有两个需要实现:新增员工修改员工首先我们先完成"新增员工"的功能开发,再完成"修改员工"的功能开发。而在"新增员工"中,需要添加头像,而头像需要用到"文件上传"技......
  • Java,反射创建对象的两种方式
    跟着孙哥学Spring,b站:https://www.bilibili.com/video/BV185411477k/?spm_id_from=333.337.search-card.all.click在Java中,我们可以使用反射来创建对象。这里有两种主要的方式:1.使用Class.forName().newInstance()方法这种方式是使用默认的无参数构造函数来创建对象。如果......
  • Java第十七课_IO流和线程
    1.IO流序列化publicclassPractice01{publicstaticvoidmain(String[]args)throwsIOException,ClassNotFoundException{//一个数据用变量//多个同类型数据用数组//多个不类型数据用对象//多......
  • docker-compose 快速运行java程序
    1、任意目录新建docker-compose.ymltouchdocker-compose.ymlmdkirconfigtouchconfig/application.yml2、复制jar文件到docker-compose.yml所在目录cp3、修改docker-compose.ymlversion:'3'services:qyweixin_server:image:image:harbor.iotwedora.com:4018......
  • Spring提供的实用纯Java工具类合集
    在SpringFramework里的spring-core核心包里面,有个org.springframework.util里面有不少非常实用的工具类。该工具包里面的工具类虽然是被定义在Spring下面的,但是由于Spring框架目前几乎成了JavaEE实际的标准了,因此我们直接使用也是无妨的,很多时候能够大大的提高我们的生产力。I......
  • JavaScript基础语句和window对象
    ifelse语句varsum=190varyouhuisum//赋予一个容器if(sum>=200){youhuisum=sum-10console.log(111)}else{//如果上面if不满足则都执行else语句......