关于Java中Random的一些使用细节

新浪微博 QQ空间

Random类相信大家都不陌生,但是必须掌握一些特定的细节才能在要求较高的场合用好该变量。这里分析一个多线程环境下Random的使用。

现在面临一个问题:有多个线程需要按照随机的方式取一个令牌,尽量让每个线程取得的令牌不一样,可以认为令牌就是一个数字,如1~100之内的一个整数。那么怎样实现能最好的解决这个问题呢?首先想到的是用一个同步的变量,使用一个getAndIncrement接口,这样每个线程调用这个接口时都能获得一个与其他同时访问该接口不一样的值。当然这不是本帖想要讨论的问题。本帖希望用随机数生成器的方式给每一个线程提供这个接口。

于是一位粗心的同学有了下面这样的接口:

public static int getRandomNumber(int scale)
{
Random random = new Random();

return random.nextInt(scale);
}

值得赞许的是,他没有直接在线程的run方法中直接使用代码,而是抽取出来作为一个接口公用,也许别处还能重用这份代码。但是在线程中使用时却发现,同一时刻,不同的线程获取到的伪随机数总是一样的,这与需求的要求不符。只有这么两行代码,函数也是可以重入的,问题出在哪里呢?

Random的实现是,在生成random实例的时候,会有一个伪随机种子,这个种子在实例创建的时候就生成了,也可以指定种子来创建实例。如果没有指定种子,则使用时间作为种子,时间的单位是纳秒,按道理来说两个时间完全撞在一起的概率也非常低了,但是实际上,在纳秒级别,时钟精度是有误差的,达不到这个精确度,因此会出现两个线程中的random实例使用了同一个种子,这样取第一个nextInt的时候也就是同一个值了。这也就是多个线程取得同一个值的原因。

那么对上述方法做一些改进,将其中的random修改为静态的成员变量可以解决该问题:

private static Random random = new Random();

public static int getRandomNumber(int scale)
{
return random.nextInt(scale);
}

这样应该就能够解决问题。但是运行时问题还是存在,还是有大量的相同的值。再看nextInt接口,是非线程安全的。加一个同步即可解决。

private static Random random = new Random();

public static int getRandomNumber(int scale)
{
synchronized (random)
{
return random.nextInt(scale);
}
}

其实这也是线程安全接口Math.random()的实现。

新浪微博 QQ空间

| 1 分2 分3 分4 分5 分 (4.86- 7票) Loading ... Loading ... | 这篇文章归档在:Java, 多线程编程, 语言基础 | 标签: , , . | 永久链接:链接 | 评论(0) |

评论

邮箱地址不会被泄露, 标记为 * 的项目必填。

8 - 2 = *



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <img alt="" src="" class=""> <pre class=""> <q cite=""> <s> <strike> <strong>

返回顶部