java多线程sync同步 和 安全

7 篇文章 0 订阅
1 篇文章 0 订阅
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内部刷新机会,做个安全机制!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值