package MultiThread.peng;
/* 拼手速抽奖案例.
1.现有一个集合装了10个奖品在里面,分别是:{“电视机”,“电冰箱”,“电脑”,“游戏机”,“洗衣机”,“空调”,“手机”,“平板电脑”,“电动车”,“电饭煲”};
2.假如有3个人同时去抽这10个奖品.最后打印出来.三个人各自都抽到了什么奖品.
例如:
张三: “电视机”,”电冰箱”,”电脑”,”游戏机”,”洗衣机”
李四: ”空调”,”手机”,”平板电脑”,
王五: ”电动车”,”电饭煲
要求:
1:3个人同时开始抽奖,每次抽奖需要使用0.5秒才能完成抽奖;
2:需要控制住同一个奖项不能同时被多个人抽走;
*/
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class P0108MultiThreads {
public static void main(String[] args) {
Runnable mr = new Runnable() {
private Random rnd;
private ArrayList<String> ls = new ArrayList<>();
{
Collections.addAll(ls, "电视机","电脑","游戏机","空调", "扫地机器人","洗衣机","音响","手机", "Pad",
"电动车","Phone", "空气净化器" );
}
@Override
public void run() {
//new Random().nextInt(Array.getLength(ls));// rint(Array.getLength(ls));
while(true) {
if (ls.toArray().length <= 0) {
System.out.println("线程 " + Thread.currentThread().getName() + " 抽奖结束");
break;
}
synchronized (this) {
if (ls.size() <= 0) {
System.out.println("线程 " + Thread.currentThread().getName() + " 抽奖结束b");
return; //加个if确保安全
}
Random rnd = new Random();
int ii = rnd.nextInt(ls.toArray().length);
System.out.println("现在是线程:" + Thread.currentThread().getName() + ", 抽到了奖品:"
+ ii + ls.get(ii));
ls.remove(ii);
try {
Thread.sleep(50); //每次睡眠50ms是为了防止某个人快速抽完所有奖品
} catch (Exception e) {
e.printStackTrace();
} //每个人依次抽奖耗时500ms,所以需要独占抽签模块;延迟在syn里面
}
}
}
};
new Thread(mr, "张三").start();
new Thread(mr, "李四").start();
new Thread(mr, "王五").start();
}
}
output
现在是线程:张三, 抽到了奖品:1电脑
现在是线程:王五, 抽到了奖品:0电视机
现在是线程:李四, 抽到了奖品:9空气净化器
现在是线程:王五, 抽到了奖品:0游戏机
现在是线程:张三, 抽到了奖品:2洗衣机
现在是线程:王五, 抽到了奖品:0空调
现在是线程:李四, 抽到了奖品:3Pad
现在是线程:王五, 抽到了奖品:3电动车
现在是线程:张三, 抽到了奖品:1音响
现在是线程:王五, 抽到了奖品:0扫地机器人
现在是线程:李四, 抽到了奖品:0手机
现在是线程:王五, 抽到了奖品:0Phone
线程 张三 抽奖结束b
线程 李四 抽奖结束b
线程 王五 抽奖结束
Process finished with exit code 0
- 用Runnable里面私有的arraylist做奖品池; 通过Random().nextInt(upperBound)来做抽奖的随机动作,注意整个抽奖流程,随机数、输出、剔除抽出的奖品是一个原子操作,必须一起;
- 延迟可以不在sync里面保证并发效率,但本次题意要求每个人抽耗时0.5s,所以正常的节奏是逐个0.5秒,依次抽(耗时10 * 0.5 = 5s)而非并发,总共差不多1s;——业务要求,sleep位于syn内部
- sync外部的size判断看似逻辑上准确,但是由于可见性问题,实际不安全。增加了if模块(结尾输出抽奖结束b)。看到张三、李四都是通过b出口结束的;特别注意变量条件的置信能力,sync内部刷新机会,做个安全机制!

该博客介绍了一个并发抽奖程序的Java实现,其中涉及多线程同步问题。程序创建了三个线程模拟三人同时抽奖,从一个奖品列表中抽取奖品,每个抽奖过程需要0.5秒。通过`synchronized`关键字保证并发安全,防止同一奖项被多次抽取。博客强调了并发控制的重要性,尤其是线程安全的实现细节和可见性问题。
866

被折叠的 条评论
为什么被折叠?



