java 中怎么得到一个不重复的数字。需求是短信提供商接口的某个参数,要求每次都提交不重复的数字。
有下列这些方式:
1、System. currentTimeMillis、 System.nanoTime。
javadoc写得很清楚,看过文档就知道不行。也可以试一下,写个循环,次数是n,循环取值放进HashSet,看最后size() 是不是n。前者粒度是毫秒,一毫秒内可以循环很多次。所以首先排除。因为总不能控制请求短信接口1ms内不请求第二次,并且控制了也没用,因为此方法返回得不是精确的ms数。
看后者取纳秒结果貌似可以,但是稍微加大循环次数,就会发现有重复的。
2、Random
还是不行。还是不用试,想一想就能明白。首先此类是个伪随机数。先不管伪不伪。
考虑一下nextInt(2)。如果调用第一次结果是1,那么第二次是不是一定是0?
想明白就知道,或者写代码试一下。然后再思考再bound扩大。比如模拟一次有2^32种可能的彩票号码。如果某一次开奖号码是29829300,那么以后会不会还可能是这个号码。显然是可能的。不然彩票号码就有迹可循了中奖号码就可预测了。因为随机事件是没有规律,至于不重复、均匀分布什么的都是一厢情愿或者自以为是,比如用Random产生随机数,如果小于某个奖品中奖概率就认为是中奖等。
那么这么思考一下,Random 构造时使用方法1的某个作为种子行不行?还是不用试明显不行。Random只是个 ( a * b + c) % d的公式,下一个是什么是可以预测的。并且是使用种子,或是每次调用都用new Random(种子)都是不行的。认为这么做可以保证不重复是一厢情愿。
因为只要种子相同,连个random对象就可以认为是同一个因为产生的随机数序列完全一致。
即使每次new时种子都不同,也不能保证。不带参构造方法就是如此,取了1的后者。还是那句,随机数只是保证没有规律,并不保证均匀分布和不重复。更不用说Random这个伪随机数。
3、hashCode
这个更不用说,知道HashMap的人都知道一定不行。即使搞java的你不知道jdk7的switch,也应该知道hash冲突这回事吧。如果用了hashCode来获取不重复数字,那真是让人十分无语又好尴尬。如果这么做了,至少说明连个hash表都没学会,并且还自以为是。
想一想,也就Byte、Short、Integer等不会有hash冲突。天天用String都冲突到火星去了。
String内是个char[],char是16位,数组长度是int类型,也就是String最多有(2^16)^(2^31)种可能,每一个字符都有2^16种可能,而int范围是2^32,两者相差一个^2,也就是说String最多只能保证length() 小于3的对象不会有hash冲突,随便找一个length()是3的都至少有一个length()小于3的对象与其冲突。
4 AotmicInteger
这个是没问题的,并且多线程也没问题,可以保证int范围内不重复,范围不够还有Long。但是我又看到延迟new还不知道加sync的单例方法,好无语,这样就不能保证只存在一个AtomicInteger对象,至于不重复也就无从谈起了。
当时情况是我写了一句:
// FIXME xxx要保证与之前不重复
并使用了AtomicInteger。写这个FIXME的意思是提醒那个延迟new又没加同步的单例方法,
后来我发现单例方法还是没加同步,并且AtomicInteger被改为了hashCode。。。。。。