Java 基于id和日期获取种子,对象数最少
我需要为洗牌创建一个种子,种子应该基于id int和当前日期,没有时间。这是为了将id的顺序保留一天,并在第二天进行更改。我现在有以下方法:Java 基于id和日期获取种子,对象数最少,java,optimization,Java,Optimization,我需要为洗牌创建一个种子,种子应该基于id int和当前日期,没有时间。这是为了将id的顺序保留一天,并在第二天进行更改。我现在有以下方法: private static long getSeedForShuffle(int id) { Date date = new Date(); Calendar cal = MyConstants.UTC_CALENDAR; cal.setTime(date); int year = cal.get(Calendar.YEA
private static long getSeedForShuffle(int id)
{
Date date = new Date();
Calendar cal = MyConstants.UTC_CALENDAR;
cal.setTime(date);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
double seed = id * 1e8 + year * 1e4 + month * 1e2 + day;
return (long) seed;
}
在MyConstants中:
public class MyConstants {
public static final Calendar UTC_CALENDAR = Calendar.getInstance(TimeZone
.getTimeZone("UTC"));
}
有没有办法避免每次调用该方法时都创建新的日期对象?i、 有比做更好的事情吗
Date date = new Date();
在getSeedForShuffle方法中,由于该方法只需要当前日期、月份和年份,因此原则上每天只能生成一次
注意:此代码正在web应用程序中运行
在阅读了《有效的Java项目5:避免创建不必要的对象》之后,我开始考虑这个问题。我没有编译这个,但可能会给您一个想法。存储一个午夜的时间戳,然后很容易看到您是否比使用系统时间调用的时间晚24小时
private static final long ONE_DAY = 1000l * 60 * 60 * 24;
private static long midnight = 0;
private static double seed = 0;
private static long getSeedForShuffle(int id)
{
if (System.currentTimeMillis() - ONE_DAY > midnight) {
Date date = new Date();
Calendar cal = MyConstants.UTC_CALENDAR;
cal.setTime(date);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
seed = id * 1e8 + year * 1e4 + month * 1e2 + day;
midnight = new Date(year, month, day).getTime();
}
return (long) seed;
}
我还没有编译这个,但可能会给你一个想法。存储一个午夜的时间戳,然后很容易看到您是否比使用系统时间调用的时间晚24小时
private static final long ONE_DAY = 1000l * 60 * 60 * 24;
private static long midnight = 0;
private static double seed = 0;
private static long getSeedForShuffle(int id)
{
if (System.currentTimeMillis() - ONE_DAY > midnight) {
Date date = new Date();
Calendar cal = MyConstants.UTC_CALENDAR;
cal.setTime(date);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
seed = id * 1e8 + year * 1e4 + month * 1e2 + day;
midnight = new Date(year, month, day).getTime();
}
return (long) seed;
}
假设每天都有相同的长度,您不需要在静态初始值设定项中分配任何内容,甚至可以消除这种情况
private static final long MILLIS_PER_DAY = 1000L * 60 * 60 * 24;
private static final long SOME_MIDNIGHT_MILLIS;
static {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
SOME_MIDNIGHT_MILLIS = calendar.getTimeInMillis();
}
private static long getSeedForShuffle(int id) {
final long millis = System.currentTimeMillis() - SOME_MIDNIGHT_MILLIS;
long days = millis / MILLIS_PER_DAY;
return 123456789 * days + id;
}
假设每天都有相同的长度,您不需要在静态初始值设定项中分配任何内容,甚至可以消除这种情况
private static final long MILLIS_PER_DAY = 1000L * 60 * 60 * 24;
private static final long SOME_MIDNIGHT_MILLIS;
static {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
SOME_MIDNIGHT_MILLIS = calendar.getTimeInMillis();
}
private static long getSeedForShuffle(int id) {
final long millis = System.currentTimeMillis() - SOME_MIDNIGHT_MILLIS;
long days = millis / MILLIS_PER_DAY;
return 123456789 * days + id;
}
这个问题归结为对给定的日期和id生成一个随机但一致的long 要提高种子的伪随机性,请对每个部分使用包装哈希代码:
private static long getSeedForShuffle(int id) {
return Long.valueOf(TimeUnit.toDays(System.currentTimeMillis())).hashCode() << 32
+ Integer.valueOf(id).hashCode();
}
要点如下:
使用System.currentTimeMillis立即获取
使用TimeUnit.toDays将现在转换为天
使用hashCode创建一致但伪随机的高质量种子值
将一个int hashCode值左移到long的高半部分,以便hashCode的所有位都参与结果
避免使用Calendar,它可以说是JDK中最坏的类
尽管此代码创建了一个Long和一个整数,但这些对象的重量非常轻,而且JIT编译器很可能会在线生成hashCode生成代码。此问题归结为为为为给定日期和id生成一个随机但一致的Long 要提高种子的伪随机性,请对每个部分使用包装哈希代码:
private static long getSeedForShuffle(int id) {
return Long.valueOf(TimeUnit.toDays(System.currentTimeMillis())).hashCode() << 32
+ Integer.valueOf(id).hashCode();
}
要点如下:
使用System.currentTimeMillis立即获取
使用TimeUnit.toDays将现在转换为天
使用hashCode创建一致但伪随机的高质量种子值
将一个int hashCode值左移到long的高半部分,以便hashCode的所有位都参与结果
避免使用Calendar,它可以说是JDK中最坏的类
尽管这段代码创建了一个Long和一个Integer,但这些对象的重量非常轻,而且JIT编译器很可能会在hashCode生成代码中嵌入它们。我明白了。种子取决于id,因此您将只保存日期部分,并将其添加到方法中的id部分。您可能应该使midnight不稳定,并且不要使用共享种子变量,否则您将有竞争条件,并且不能再保证排序。他只是想避免创建对象。诚然,在我的游戏中,你可以多次生成种子,但结果总是一样的,而且它只会在翻滚当天的比赛条件下发生。所以我不想为同步或volatile而烦恼,除非这是个问题。还有一件事,为了支持我的观点,将分、时、秒设置为零,以确保seed完全相同。我明白了。种子取决于id,因此您将只保存日期部分,并将其添加到方法中的id部分。您可能应该使midnight不稳定,并且不要使用共享种子变量,否则您将有竞争条件,并且不能再保证排序。他只是想避免创建对象。诚然,在我的游戏中,你可以多次生成种子,但结果总是一样的,而且它只会在翻滚当天的比赛条件下发生。因此,我不会为同步或volatile而烦恼,除非这是一个问题。还有一件事,为了支持我的情况,将分钟、小时、秒设置为零,以确保seed完全相同。我不会将该特定示例称为不必要的对象创建,因为回收对象会产生各种各样的问题,例如线程安全问题,除非每秒调用数百次该方法,否则这些问题都不值得我这么做。另外,您是否有强烈的理由希望种子以日期为基础?如果你需要排序,一个简单的递增计数器,或者如果排序不重要,甚至是一个随机数都会更容易。我们需要维持一天的顺序,因为我们正在做一些A/B测试。我们的页面被缓存了几分钟,但无法承受每次对象为c时的新随机顺序
此外,如果您使用的数据库至少是SQL,也可能使用其他数据库,则可以轻松获得通用的唯一递增id。不要忘记日历不是线程安全的。如果要防止分配,请使用ThreadLocal。我不会将该特定示例称为不必要的对象创建,因为循环使用该对象将产生各种问题,例如线程安全问题,除非该方法每秒调用数百次,否则这些问题都是不值得的。另外,您是否有强烈的理由希望种子以日期为基础?如果你需要排序,一个简单的递增计数器,或者如果排序不重要,甚至是一个随机数都会更容易。我们需要维持一天的顺序,因为我们正在做一些A/B测试。我们的页面会被缓存几分钟,但无法承受每次创建对象时的新随机顺序。此外,如果您使用数据库(至少使用SQL),也可能使用其他数据库,则可以轻松获得通用唯一递增id。别忘了日历不是线程安全的。如果要防止分配,请使用ThreadLocal。