Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基于id和日期获取种子,对象数最少_Java_Optimization - Fatal编程技术网

Java 基于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

我需要为洗牌创建一个种子,种子应该基于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.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。