欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

7道练习题:Java多线程(第五部分)

最编程 2024-08-11 18:06:35
...

练习

多线程练习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 + "元");
 }
}


推荐阅读