我要求我不断收到需要写入文件的消息。每次收到新消息时,都需要将其写入单独的文件中。我想要的是生成一个唯一的标识符用作文件名。我也想保留消息的顺序。我的意思是,作为文件名生成的标识符应该始终是增量的。
我使用 UUID.randomUUID()来生成文件名,但这种方法的问题是UUID只保证标识符的随机性,但不是增量式的。结果我丢失了文件的顺序(我希望首先生成的文件应首先出现在列表中)。
已知方法
2.另一种方法可以是实现静态long值,并在创建文件时递增它,并将long值用作文件名。但我不确定这种方法。此外,它似乎不是我的问题的正确解决方案。我认为可能有比这更好的解决方案。
如果有人可以建议我更好地解决这个问题,我们将非常感激。
答案 0 :(得分:4)
如果您希望您的id值在服务器重新启动之间均匀上升,那么您必须以系统时间为基础,或者使用一些精心构建的强大逻辑来保留最后使用的ID。请注意,实现稳健性并不难,但以高性能和可扩展的方式实现它是。
如果您还需要在冗余服务器群集中的多个节点上使用id唯一,那么您需要更复杂的逻辑,这肯定涉及所有框同步访问的持久性存储。当然,提高性能是更难的。
我能看到的最佳选择是拥有一个很长的ID,因此这些部分有空间:
System.currentTimeMillis
用于长期唯一性(跨重启); System.nanotime
以获得更精细的粒度; 该方法仍然需要记住生成的最后一个值,并在重复的情况下重试。但是,它不必重试太多次,直到下一个nanoTime
时钟滴答 - 它甚至可能忙 - 等待它。
没有第3点的代码草图(单节点实现):
private static long lastNanos;
public static synchronized String uniqueId() {
for (;/*ever*/;) {
final long n = System.nanoTime();
if (n == lastNanos) continue;
lastNanos = n;
return "" + System.currentTimeMillis() + n;
}
}
答案 1 :(得分:0)
好的,我的举手。我的最后一个答案是相当不稳定的,我删除了它。
保持网站的精神,我以为我会尝试不同的tac。
如果您说您将这些邮件保存在一个文件中,那么您可以尝试创建一个超出文件大小的唯一ID吗?
在将消息写入文件之前,它的id可能是文件的当前大小。
如果这些消息需要在多个文件中唯一,您可以添加文件名+大小作为ID。
我会将同步的烫手山芋留到另一天。但是你可以将所有这些包装在一个跟踪事物的同步对象中。
此外,我假设将来不会删除写入该文件的任何邮件。
附加说明: 您可以创建一个消息处理对象,在构造时(或通过create方法)打开文件。 此对象将获取文件的初始大小,这将用作唯一ID。 随着每条消息的添加(以同步方式),id将增加消息的大小。 这将解决性能问题。如果多个JVM / Node访问同一个文件,则无效。
骨骼想法:
public class MessageSink {
private long id = 0;
public MessageSink(String filename) {
id = ... get file size ..
}
public synchronized addMessage(Message msg) {
msg.setId(id);
.. write to file + flush ..
.. or add to stack of messages that need to be written to file
.. at a later stage.
id = id + msg.getSize();
}
public void flushMessages() {
.. open file
.. for each message in stack write ...
.. flush and close file
}
}
答案 2 :(得分:0)
我有相同的要求并找到了合适的解决方案。 Twitter Snowflake使用一种简单的算法来生成可排序的64位(长)ID 。 Snowflake是在Scala上编写的,但方法很简单,可以很容易地在Java代码中使用。
id由以下内容组成: timestamp - 41位(毫秒级精度w /自定义时代给我们69年); machine id - 10位(MAC地址可用作硬件ID); 序列号 - 12位 - 每台机器每4096个滚动一次(带保护以避免在相同的时间内翻转)
公式如下:((timestamp - customEpoch) << timestampShift) | (machineId << machineIdShift) | sequenceNumber;
每个组件的移位取决于它在ID中的位位置。
详细说明和源代码可以在github找到: