我正在編寫一個類,該類在調用時會調用一個方法來使用系統時間來生成唯一的8個字符的字母數字作爲參考ID。但是我擔心在某些時候,多個呼叫可能會在同一毫秒內完成,從而產生相同的參考ID。我怎麼能保護這個調用來自可能同時調用此方法的多個線程的系統時間?如何同步Java中的類中的系統時間訪問
回答
系統時間是唯一ID的不可靠來源。而已。不要使用它。 您需要某種形式的永久性來源(UUID使用安全隨機,種子由操作系統提供)
系統時間可能會向後跳躍(甚至幾毫秒),並完全顛覆您的邏輯。如果你只能容忍64位,你可以使用High/Low generator這是一個非常好的折衷方案,或者自己製作食譜:比如自2012年初以來的18個天(你有超過700年的時間),然後是來自SecureRandom的46位隨機性 - 不是最好的情況和技術上它可能會失敗,但它不需要外部持久性。
老實說,如果你提出的問題如同步系統時間,你不應該寫自己的。使用已經過驗證的真正的'UUID'生成算法,而不是自制的:-) –
UUID只是安全的隨機數和2個longs +設置所需的位以符合UUID規範。但是,是的,同意不會就SO時間提出關於同步時間的問題,並嘗試單獨進行下一步。然而,嘗試自己的東西,失敗,重新嘗試,學習的方式也是如此。 – bestsss
我建議將threadID添加到參考ID。這將使參考更加獨特。但是,即使在一個線程中,對時間源的連續調用也可能會傳遞相同的值。即使調用最高分辨率源(QueryPerformanceCounter)也可能會在某些硬件上產生相同的值。解決這個問題的一個可能的方法是對上一次收集的時間值進行測試,並將增量項添加到「時間戳」中。這應該是人類可讀的,你可能需要超過8個字符。 時間戳最有效的來源是GetSystemTimeAsFileTime API。我在this的答案中寫了一些細節。
您可以使用UUID
類爲您的ID生成位,然後使用一些按位運算符和Long.toString
將其轉換爲基數36(字母數字)。
public static String getId() {
UUID uuid = UUID.randomUUID();
// This is the time-based long, and is predictable
long msb = uuid.getMostSignificantBits();
// This contains the variant bits, and is random
long lsb = uuid.getLeastSignificantBits();
long result = msb^lsb; // XOR
String encoded = Long.toString(result, 36);
// Remove sign if negative
if (result < 0)
encoded = encoded.substring(1, encoded.length());
// Trim extra digits or pad with zeroes
if (encoded.length() > 8) {
encoded = encoded.substring(encoded.length() - 8, encoded.length());
}
while (encoded.length() < 8) {
encoded = "0" + encoded;
}
}
由於相比UUID
你的性格空間仍然較小,這並非萬無一失。使用以下代碼進行測試:
public static void main(String[] args) {
Set<String> ids = new HashSet<String>();
int count = 0;
for (int i = 0; i < 100000; i++) {
if (!ids.add(getId())) {
count++;
}
}
System.out.println(count + " duplicate(s)");
}
對於100,000個ID,代碼執行得非常穩定,速度非常快。
當我將另一個數量級增加到1,000,000時,我開始獲取重複ID。
我修改了修剪以取代編碼字符串的末尾而不是開頭,這大大提高了重複ID率。現在有1,000,000個ID不會爲我生成任何重複項。
您最好的選擇仍然是使用同步計數器,如AtomicInteger
或AtomicLong
,並使用上面的代碼對base-36中的數字進行編碼,特別是如果您打算擁有大量ID。
編輯:櫃檯的方式,如果你想它:
private final AtomicLong counter;
public IdGenerator(int start) {
// start could also be initialized from a file or other
// external source that stores the most recently used ID
counter = new AtomicLong(start);
}
public String getId() {
long result = counter.getAndIncrement();
String encoded = Long.toString(result, 36);
// Remove sign if negative
if (result < 0)
encoded = encoded.substring(1, encoded.length());
// Trim extra digits or pad with zeroes
if (encoded.length() > 8) {
encoded = encoded.substring(0, 8);
}
while (encoded.length() < 8) {
encoded = "0" + encoded;
}
}
此代碼是線程安全的,可以同時訪問。
- 1. 如何同步系統日期/時間?
- 2. java中的時間同步
- 3. lighttpd和系統之間的訪問權限同步
- 4. 訪問java中的同步方法
- 5. 從java中的系統輸入時間
- 6. 在Android中同步系統時間的應用程序的時間
- 7. 如何在Ubuntu系統中導入java中的joda時間
- 8. Java中的系統類
- 9. 2個系統之間的同步
- 10. 如何訪問電池的剩餘時間在android系統
- 11. 如何以2毫秒的精度同步2個系統之間的時間?
- 12. 訪問當前系統時間區
- 13. 在兩部手機中同步系統時間
- 14. <ctime>中的clock()函數如何訪問系統時鐘?
- 15. 如何在java編程中從系統訪問文件到另一個系統?
- 16. 在java中的類同步
- 17. 如何訪問Java中不同類中方法的變量?
- 18. 在Java中修改系統時間
- 19. 如何從系統中訪問系統jboss文件夾中的文件
- 20. 訪談問:Java同步
- 21. 如何訪問Java中的子子類?
- 22. 如何計算內存系統延遲(訪問時間)?
- 23. 如何將時間保存在與系統時間不同的變量中?
- 24. 如何從Java中的多個類訪問相同的對象
- 25. 如何訪問不同類中的NSURLResponse
- 26. 如何與java日曆同步時間
- 27. 如何從系統中獲取時間?
- 28. Android中的同步時間
- 29. Jira Tempo - 與外部系統同步已刪除的時間
- 30. 通過VBA(訪問/ Excel)中獲取系統運行時間
是否有一個原因,你不能使用['UUID'](http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html)?它的一代更安全。 – Brian
我相信UUID也使用系統時間,但我需要它是8個字符長,最大... – Aaron
它使用系統時間,是的,但它也使用其他的東西,如'SecureRandom'(見[這個問題](http://stackoverflow.com/questions/2513573/how-good-is-javas-uuid-randomuuid) )。你可以詢問'UUID'的位(它有128個,2個「長」值,這對於8個字符是足夠的),並用它來獲取字符。 – Brian