巧用random方法,事半功倍

210 阅读2分钟

最近遇到一个紧急需求如下:公司需要线上开展一次拉新活动,十元拼团,三人成团,为了提高用户拼团成功,刺激购买,每个用户打开链接,显示拼团进行中,同时已有2个虚拟用户,虚拟用户头像取500个头像中随机,要求同一个用户进去已拼团的2个用户头像不变。

很快作为一名研发,马上理解了需求,准备开始动工。由于此需要比较紧急,将采用最简单的方式进行处理。因此我们直接将500个头像,直接录入到数据库,此时发现最终变成取头像这样一个算法问题,即随机取出,同时保证同一个用户得到的随机结果永远一样,作为一名有经验的研发人员,可以想到了使用userId来做文章,此时我们采用写出了一段代码

public class Demo {
    public static void main(String[] args) {
        User user = new User();
        user.setId(1234L);
        user.setName("ganhuojun");
        user.setMoblie("13912345678");

        for (int i = 0; i < 10; i++) {
            System.out.println(Math.abs(user.getId().hashCode() % 500));
            System.out.println(Math.abs(user.getName().hashCode() % 500));
            System.out.println(Math.abs(user.getMoblie().hashCode() % 500));
        }
    }
}

User为用户

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Long id;

    private String name;

    private Integer age;

    private String address;

    private String moblie;

}

针对运行代码结果永远是确定值,如下图

234
157
165

这样我们保证了用户任何时候访问,拼团的头像的不变,且不会用到数据库。

很快,有人提出了用户万一修改了用户名和手机号怎么办?

对于用户来说,userId才应该是唯一的,接下来的问题,变成是否可以单独使用userId来获取几个固定的随机值。因此我们转入研究Random类,如下图

发现,Random()无参构造器,最终访问了一个有参数构造器,

public Random(long seed) {
    if (getClass() == Random.class)
        this.seed = new AtomicLong(initialScramble(seed));
    else {
        // subclass might have overriden setSeed
        this.seed = new AtomicLong();
        setSeed(seed);
    }
}

synchronized public void setSeed(long seed) {
   this.seed.set(initialScramble(seed));
   haveNextNextGaussian = false;
}

通过源码发现seed是随机数种子,一旦种子一样,获得的结果一样,算法如下

因此立刻想到了,我们将用户的userId作为种子,必然会得出一样的随机值,从而确保每次请求结果不变,所以将代码改成

public class Demo {
    public static void main(String[] args) {
        User user = new User();
        user.setId(1234L);
        user.setName("ganhuojun");
        user.setMoblie("13912345678");

        Random random = new Random();
        for (int i = 0; i < 10 ; i++) {
            random.setSeed(user.getId());
            System.out.println(random.nextInt(500)); // 128
            System.out.println(random.nextInt(500)); // 133
            System.out.println(random.nextInt(500)); // 133
        }

    }
}

注意去除重操作。

结论

主要利用了随机数的seed属性,保证每次请求结果不变,从而避免数据存库操作,达到事半功倍的效果。

欢迎关注我的公众号,一个只分享干货的公众号~~~