练习一:售票
需求:一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,请用多线程模拟卖票过程并打印剩余电影票的数量。
多个线程操作共享数据。
线程类:
public class ThreadDemo1 extends Thread{
static int ticket = 1000;
@Override
public void run() {
while (true) {
synchronized (ThreadDemo1.class) {
if (ticket == 0) {
break;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
ticket--;
System.out.println("剩余" + ticket + "张电影票");
}
}
}
}
测试类:
public class Test1 {
public static void main(String[] args) {
ThreadDemo1 t1 = new ThreadDemo1();
ThreadDemo1 t2 = new ThreadDemo1();
t1.setName("窗口一");
t2.setName("窗口二");
t1.start();
t2.start();
}
}
练习二:赠送礼物
需求:有100份礼品,两人同时发送,当剩下的礼品小于10份的时候则不再送出。
利用多线程模拟该过程并将线程的名字和礼物的剩余数量打印出来。
线程类:
public class ThreadDemo2 extends Thread{
static int ticket = 100;
@Override
public void run() {
while (true)
synchronized (ThreadDemo2.class) {
if (ticket < 10) {
break;
}
ticket--;
System.out.println(this.getName() + ":剩余" + ticket + "份礼物");
}
}
}
测试类:
public class Test2 {
public static void main(String[] args) {
ThreadDemo2 t1 = new ThreadDemo2();
ThreadDemo2 t2 = new ThreadDemo2();
t1.setName("小刘");
t2.setName("小张");
t1.start();
t2.start();
}
}
练习三:打印数字
需求:同时开启两个线程,共同获取1-100之间的所有数字。
将输出所有的奇数。
线程类:
public class ThreadDemo3 extends Thread{
static int number = 1;
@Override
public void run() {
while (true) {
synchronized (ThreadDemo3.class) {
if (number > 100) {
break;
}
if (number % 2 != 0) {
System.out.println(number);
}
number++;
}
}
}
}
测试类:
public class Test3 {
public static void main(String[] args) {
ThreadDemo3 t1 = new ThreadDemo3();
ThreadDemo3 t2 = new ThreadDemo3();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
练习四:抢红包
需求:
抢红包也用到了多线程。
假设:100块,分成了3个包,现在有5个人去抢。
其中,红包是共享数据。
5个人是5条线程。
打印结果如下:
XXX抢到了XXX元
XXX抢到了XXX元
XXX抢到了XXX元
XXX没抢到
XXX没抢到
线程类:
import java.util.Random;
public class ThreadDemo4 extends Thread {
// 总钱数
static int totalMoney = 100;
// 3个人抢到红包
static int count = 1;
final int MIN = 1;
@Override
public void run() {
synchronized (ThreadDemo4.class) {
// 3个红包已抢完
if (count == 4) {
System.out.println(this.getName() + "没抢到");
}
// 第3个红包直接就是剩下的钱
if (count == 3) {
System.out.println(this.getName() + "抢了" + totalMoney + "元");
count++;
}
if (count <= 2) {
Random r = new Random();
int money = r.nextInt(totalMoney - MIN * (3 - count)) + MIN;
System.out.println(this.getName() + "抢了" + money + "元");
totalMoney -= money;
count++;
}
}
}
}
关于此题,每个线程的run方法只执行一次,如何保证每个线程只抽一次?因为抽完线程就die了,不会再运行了。Java中线程的6个状态。
练习五:抽奖箱
需求:
有一个抽奖池,该抽奖池中存放了奖励的金额,该抽奖池中的奖项为 {10,5,20,50,100,200,500,800,2,80,300,700};
创建两个抽奖箱(线程)设置线程名称分别为“抽奖箱1”,“抽奖箱2”。
随机从抽奖池中获取奖项元素并打印在控制台上,格式如下:
每次抽出一个奖项就打印一个(随机)
抽奖箱1 又产生了一个 10 元大奖
抽奖箱1 又产生了一个 100 元大奖
抽奖箱1 又产生了一个 200 元大奖
抽奖箱1 又产生了一个 800 元大奖
抽奖箱2 又产生了一个 700 元大奖
将奖项放在集合中。随机获取索引,而集合中有一个remove方法在依据索引删除元素时会将删除的元素进行返回。或者利用工具类Collections的shuffle方法打乱元素,然后也是利用remove删除0索引处的元素并进行返回。
线程类:
import java.util.ArrayList;
import java.util.Random;
public class ThreadDemo5 extends Thread {
ArrayList<String> list;
public ThreadDemo5(ArrayList<String> list) {
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (ThreadDemo5.class) {
int length = list.size();
if (length == 0) {
break;
}
Random r = new Random();
int index = r.nextInt(length);
System.out.println(this.getName() + "又产生了一个"+list.remove(index)+"元大奖");
}
}
}
}
public class Test5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "10", "5", "20", "50", "100", "200", "500", "800", "2", "80", "300", "700");
ThreadDemo5 t1 = new ThreadDemo5(list);
ThreadDemo5 t2 = new ThreadDemo5(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}
练习六:多线程统计并求最大值
需求:
在上一题基础上继续完成如下需求:
每次抽的过程中,不打印,抽完时一次性打印(随机)
在此次抽奖过程中,抽奖箱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.Random;
public class ThreadDemo6 extends Thread {
ArrayList<Integer> list;
public ThreadDemo6(ArrayList<Integer> list) {
this.list = list;
}
@Override
public void run() {
ArrayList<Integer> list1 = new ArrayList<>();
while (true) {
synchronized (ThreadDemo6.class) {
int length = list.size();
if (length == 0) {
int max = 0, sum = 0;
for (Integer prize : list1) {
sum += prize;
if (prize > max) {
max = prize;
}
}
System.out.println("此次抽奖过程中," + this.getName() + "总共产生了" + list1.size() + "个奖项。");
System.out.print("分别为:");
for (Integer i : list1) {
System.out.print(i + ",");
}
System.out.println("最高奖项为" + max + "元,总计金额为" + sum + "元");
break;
}
Random r = new Random();
int index = r.nextInt(length);
list1.add(list.remove(index));
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
测试类:
import java.util.ArrayList;
import java.util.Collections;
public class Test6 {
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);
ThreadDemo6 t1 = new ThreadDemo6(list);
ThreadDemo6 t2 = new ThreadDemo6(list);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}
练习七:多线程之间的比较
需求:
在上一题基础上继续完成如下需求:
在此次抽奖过程中,抽奖箱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.Random;
public class ThreadDemo7 extends Thread {
ArrayList<Integer> list;
int maxPrize;
public ThreadDemo7(ArrayList<Integer> list, int maxPrize) {
this.list = list;
this.maxPrize = maxPrize;
}
@Override
public void run() {
ArrayList<Integer> list1 = new ArrayList<>();
while (true) {
synchronized (ThreadDemo7.class) {
int length = list.size();
if (length == 0) {
int max = 0, sum = 0;
for (Integer prize : list1) {
sum += prize;
if (prize > max) {
max = prize;
}
}
System.out.println("此次抽奖过程中," + this.getName() + "总共产生了" + list1.size() + "个奖项。");
System.out.print("分别为:");
for (Integer i : list1) {
System.out.print(i + ",");
}
System.out.println("最高奖项为" + max + "元,总计金额为" + sum + "元");
if (max == maxPrize) {
System.out.println("在此次抽奖过程中," + this.getName() + "中产生了最大奖项,该奖项金额为" +max +"元");
}
break;
}
Random r = new Random();
int index = r.nextInt(length);
list1.add(list.remove(index));
}
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
测试类:
import java.util.ArrayList;
import java.util.Collections;
public class Test7 {
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);
int maxPrize = 0;
for (Integer i : list) {
if (i > maxPrize) {
maxPrize = i;
}
}
ThreadDemo7 t1 = new ThreadDemo7(list, maxPrize);
ThreadDemo7 t2 = new ThreadDemo7(list,maxPrize);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
}
}
还可以利用线程的抵第3种创建方式,将结果进行返回。
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 //2
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(10);
}
//把集合中的最大值返回
if(boxList.size() == 0){
return null;
}else{
return Collections.max(boxList);
}
}
}