练习一:售票
需求:一共有1000张电影票,可以在两个窗口领取,假设每次领取的时间为3000毫秒,请用多线程模拟卖票过程并打印剩余电影票的数量。
多个线程操作共享数据。
线程类:
public class ThreadDemo1 extends Thread{static int ticket = 1000;@Overridepublic 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;@Overridepublic 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;@Overridepublic 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;@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic Integer call() throws Exception {ArrayList<Integer> boxList = new ArrayList<>();//1 //2while (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);}}
}