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