2012-10-16 75 views
1

我有,我不斷收到一個需要在文件中寫入信息需求增量標識。每次收到新消息時,都需要將其寫入單獨的文件中。我想要的是生成一個唯一的標識符作爲文件名。我也想保留消息的順序。我的意思是,作爲文件名生成的標識符應該始終是增量式的。如何生成Java

我使用UUID.randomUUID()來生成文件名,但這種方法的問題是UUID只能確保標識符的隨機性,但不是增量式的。因此,我失去了文件的順序(我希望首先生成的文件應該首先出現在列表中)。衆所周知

  1. 方法可以使用System.currentTimeMillis的(),但我可以接收在同一時間標記多條消息。

2.另一種方法可以是實現靜態長整型值,並在創建文件時將其遞增並將長整型值用作文件名。但我不確定這種方法。此外,它似乎不是我的問題的適當解決方案。我認爲可能會有比這更好的解決方案。

如果有人能建議我一個更好的解決這個問題,將不勝感激。

+1

我只是一個每次添加一個BigInteger具有較高基超過10 – AJcodez

+0

可以叔你在uuid上加上時間戳?所以你們都保存命令(時間戳)並且在ID中有隨機性 – phury

+0

@AJcodez:你可以用一個例子來解釋上面的方法嗎?它可以幫助我更好地理解。 –

回答

4

如果你想你的價值的ID,甚至服務器重新啓動之間均勻上升,那麼您必須作爲它的基礎上的系統時間還是有一些精心強大的邏輯仍然存在最後使用的ID。請注意,自己實現穩健性並不難,但以高性能和可擴展的方式實現它就是了。

如果您需要額外的ID是跨多個節點獨特的冗餘服務器集羣,那麼你需要更復雜的邏輯,這肯定涉及到所有的箱子同步訪問持久性存儲。製造這種性能當然更難。

我能看到的最好的辦法是有一個相當長的ID,以便有足夠的空間用於以下幾個部分:長期的獨特

  1. System.currentTimeMillis(橫跨重新啓動);
  2. System.nanotime爲更精細的粒度;
  3. 每個服務器節點的唯一ID(以平臺特定的方式確定)。

該方法仍然需要記住上次生成的值,並在重複的情況下重試。不過,它不會重試太多次,直到下一個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; 
    } 
} 
+0

我已經刪除了我公認的片狀答案,並投了你的票。請儘量不要在未來的評論中對他人產生過激的態度。 –

+0

@AdrianRegan對不起,我沒有注意到積極的語氣(有時會滑倒,我猜)。很容易混淆直接口吻和侵略性。爲了記錄,我沒有downvote你的解決方案:) –

+0

沒問題。但你本來是對的。我需要咖啡......-) –

0

好了,我的手。我最後的回答非常片斷,我刪除了它。

與網站的精神,我想我會嘗試不同的TAC。

如果你說你將這些消息保存在一個單獨的文件中,那麼你可以嘗試一些東西,比如創建一個超出文件大小的唯一ID。

在將消息寫入文件之前,它的id可能是文件的當前大小。

如果這些消息需要在多個文件中唯一,您可以將文件名+大小添加爲ID。

我將離開熱土豆的同步到另一天。但是你可以將所有這些都包含在一個跟蹤事物的syncronized對象中。

此外,我假設任何寫入該文件的消息將不會被刪除。

附加說明: 您可以創建一個消息處理對象,用於在構造(或通過create方法)上打開文件。 該對象將獲得文件的初始大小,並將用作唯一標識。 隨着每個消息被添加(以同步的方式),該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 
    } 
} 
+0

這可以工作(和一個非常聰明的主意!),但我看到的問題是,該文件將不得不始終保持開放狀態,並且可能會遇到平臺特定的問題,以確定當前打開的文件的大小。不斷打開和關閉文件可以解決這個問題,但可能會導致性能不佳。 –

+0

我將始終在一個文件中保留固定數量的消息。此外,如果有的話,這些消息也可以具有相同的長度並稍微有輕微的變化。這些存儲的消息不是永久的。一旦我處理完文件,我將徹底清除這些文件。 –

+0

我認爲這將發生在'tranactional'上下文中,即打開,獲取大小,寫入,關閉,刷新。它會很慢,但由於@Ankur已經寫入了一個文件,它可以被合併到這個功能中。我不知道有多少消息到達或速率。但是,如果它很慢,而不是時間關鍵? –

0

我有同樣的要求,找到一個合適的解決方案。 Twitter Snowflake使用簡單的算法來生成可分類的64位(長)ID的。 Snowflake寫在Scala上,但方法很簡單,可以很容易地用在Java代碼中。

id由以下組成: 時間戳 - 41位(毫秒精度w /自定義曆元給我們69年); 機器ID - 10位(MAC地址可以用作硬件ID); 序號 - 12位 - 在每4096個每機(帶保護,以避免在同一毫秒側翻)

式看起來輥等:((timestamp - customEpoch) << timestampShift) | (machineId << machineIdShift) | sequenceNumber;

移位用於每個組件依賴於它在ID比特位置。

詳細說明和源代碼可以在github上找到:

Twitter Snowflake

Basic Java implementation of the Snowflake algorithm