2. 多线程综合练习
练习一:售票
需求:
一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,
请用多线程模拟卖票过程并打印剩余电影票的数量
代码示例:
public class MyThread extends Thread {
//第一种方式实现多线程,测试类中MyThread会创建多次,所以需要加staticstatic int ticket = 1000;
@Overridepublic void run() {//1.循环while (true) {//2.同步代码块synchronized (MyThread.class) {//3.判断共享数据(已经到末尾)if (ticket == 0) {break;} else {//4.判断共享数据(没有到末尾)try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}ticket--;System.out.println(getName() + "在卖票,还剩下" + ticket + "张票!!!");}}}}
}
public class Test {public static void main(String[] args) {/*一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,要求:请用多线程模拟卖票过程并打印剩余电影票的数量*/
//创建线程对象MyThread t1 = new MyThread();MyThread t2 = new MyThread();
//给线程设置名字t1.setName("窗口1");t2.setName("窗口2");
//开启线程t1.start();t2.start();
}
}
练习二:赠送礼物
需求:
有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。
利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来.
public class MyRunable implements Runnable {
//第二种方式实现多线程,测试类中MyRunable只创建一次,所以不需要加staticint count = 100;
@Overridepublic void run() {//1.循环while (true) {//2.同步代码块synchronized (MyThread.class) {//3.判断共享数据(已经到末尾)if (count < 10) {System.out.println("礼物还剩下" + count + "不再赠送");break;} else {//4.判断共享数据(没有到末尾)count--;System.out.println(Thread.currentThread().getName() + "在赠送礼物,还剩下" + count + "个礼物!!!");}}}}
}
public class Test {public static void main(String[] args) {/*有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出,利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来.*/
//创建参数对象MyRunable mr = new MyRunable();
//创建线程对象Thread t1 = new Thread(mr,"窗口1");Thread t2 = new Thread(mr,"窗口2");
//启动线程t1.start();t2.start();}
}
练习三:打印数字
需求:
同时开启两个线程,共同获取1-100之间的所有数字。
将输出所有的奇数。
public class MyRunable implements Runnable {
//第二种方式实现多线程,测试类中MyRunable只创建一次,所以不需要加staticint number = 1;
@Overridepublic void run() {//1.循环while (true) {//2.同步代码块synchronized (MyThread.class) {//3.判断共享数据(已经到末尾)if (number > 100) {break;} else {//4.判断共享数据(没有到末尾)if(number % 2 == 1){System.out.println(Thread.currentThread().getName() + "打印数字" + number);}number++;}}}}
}
public class Test {public static void main(String[] args) {/*同时开启两个线程,共同获取1-100之间的所有数字。要求:将输出所有的奇数。*/
//创建参数对象MyRunable mr = new MyRunable();
//创建线程对象Thread t1 = new Thread(mr,"线程A");Thread t2 = new Thread(mr,"线程B");
//启动线程t1.start();t2.start();}
}
练习四:抢红包
需求:
抢红包也用到了多线程。
假设:100块,分成了3个包,现在有5个人去抢。
其中,红包是共享数据。
5个人是5条线程。
打印结果如下:
XXX抢到了XXX元
XXX抢到了XXX元
XXX抢到了XXX元
XXX没抢到
XXX没抢到
解决方案一:
public class MyThread extends Thread{
//共享数据//100块,分成了3个包static double money = 100;static int count = 3;
//最小的中奖金额static final double MIN = 0.01;
@Overridepublic void run() {//同步代码块synchronized (MyThread.class){if(count == 0){//判断,共享数据是否到了末尾(已经到末尾)System.out.println(getName() + "没有抢到红包!");}else{//判断,共享数据是否到了末尾(没有到末尾)//定义一个变量,表示中奖的金额double prize = 0;if(count == 1){//表示此时是最后一个红包//就无需随机,剩余所有的钱都是中奖金额prize = money;}else{//表示第一次,第二次(随机)Random r = new Random();//100 元 3个包//第一个红包:99.98//100 - (3-1) * 0.01double bounds = money - (count - 1) * MIN;prize = r.nextDouble(bounds);if(prize < MIN){prize = MIN;}}//从money当中,去掉当前中奖的金额money = money - prize;//红包的个数-1count--;//本次红包的信息进行打印System.out.println(getName() + "抢到了" + prize + "元");}}}
}
public class Test {public static void main(String[] args) {/*微信中的抢红包也用到了多线程。假设:100块,分成了3个包,现在有5个人去抢。其中,红包是共享数据。5个人是5条线程。打印结果如下:XXX抢到了XXX元XXX抢到了XXX元XXX抢到了XXX元XXX没抢到XXX没抢到*/
//创建线程的对象MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();MyThread t4 = new MyThread();MyThread t5 = new MyThread();
//给线程设置名字t1.setName("小A");t2.setName("小QQ");t3.setName("小哈哈");t4.setName("小诗诗");t5.setName("小丹丹");
//启动线程t1.start();t2.start();t3.start();t4.start();t5.start();}
}
解决方案二:
public class MyThread extends Thread{
//总金额static BigDecimal money = BigDecimal.valueOf(100.0);//个数static int count = 3;//最小抽奖金额static final BigDecimal MIN = BigDecimal.valueOf(0.01);
@Overridepublic void run() {synchronized (MyThread.class){if(count == 0){System.out.println(getName() + "没有抢到红包!");}else{//中奖金额BigDecimal prize;if(count == 1){prize = money;}else{//获取抽奖范围double bounds = money.subtract(BigDecimal.valueOf(count-1).multiply(MIN)).doubleValue();Random r = new Random();//抽奖金额prize = BigDecimal.valueOf(r.nextDouble(bounds));}//设置抽中红包,小数点保留两位,四舍五入prize = prize.setScale(2,RoundingMode.HALF_UP);//在总金额中去掉对应的钱money = money.subtract(prize);//红包少了一个count--;//输出红包信息System.out.println(getName() + "抽中了" + prize + "元");}}}
}
public class Test {public static void main(String[] args) {/*微信中的抢红包也用到了多线程。假设:100块,分成了3个包,现在有5个人去抢。其中,红包是共享数据。5个人是5条线程。打印结果如下:XXX抢到了XXX元XXX抢到了XXX元XXX抢到了XXX元XXX没抢到XXX没抢到*/
MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();MyThread t4 = new MyThread();MyThread t5 = new MyThread();
t1.setName("小A");t2.setName("小QQ");t3.setName("小哈哈");t4.setName("小诗诗");t5.setName("小丹丹");
t1.start();t2.start();t3.start();t4.start();t5.start();}
}
练习五:抽奖箱
需求:
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1 又产生了一个 10 元大奖
抽奖箱1 又产生了一个 100 元大奖
抽奖箱1 又产生了一个 200 元大奖
抽奖箱1 又产生了一个 800 元大奖
抽奖箱2 又产生了一个 700 元大奖
.....
public class MyThread extends Thread {
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) {this.list = list;}
@Overridepublic void run() {//1.循环//2.同步代码块//3.判断//4.判断
while (true) {synchronized (MyThread.class) {if (list.size() == 0) {break;} else {//继续抽奖Collections.shuffle(list);int prize = list.remove(0);System.out.println(getName() + "又产生了一个" + prize + "元大奖");}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
}}
}
public class Test {public static void main(String[] args) {/*有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:每次抽出一个奖项就打印一个(随机)抽奖箱1 又产生了一个 10 元大奖抽奖箱1 又产生了一个 100 元大奖抽奖箱1 又产生了一个 200 元大奖抽奖箱1 又产生了一个 800 元大奖抽奖箱2 又产生了一个 700 元大奖.....*/
//创建奖池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("抽奖箱1");t2.setName("抽奖箱2");
//启动线程t1.start();t2.start();}
}