パッケージcom.shopping.test; インポートは、java.text.SimpleDateFormat; インポートjava.util.Date; / ** *** *アルゴリズムは、タイムスタンプに基づいて雪命じたロングタイプの64ビットの一意のIDを生成する * 各ビットの意味* : * 1「ビット:符号ビット、0はIDが正の数であり、1の正の数が負であるので、一定の撮影0 * 41である」ビット:時間差は、我々が現在の時間差を計算するために使用される基準点を選択することができ(ミリ秒) 、十分に69年間使用する41ビット蓄積時間差 10ビット*:マシンコードは、1024台のマシンをコードは、手動で、機械番号として前者5ビットの意味を示し、プロセス番号として5ビット ×12ビットのシリアル番号、同じMSは、12ビットのシーケンス番号が4096をサポートすることができ、異なるシリアル番号と同じマシンで発生 :長所* *柔軟な構成:意味をコードする柔軟なニーズに応じて構成することができるが ない持続性を*ない:シーケンス番号の増分は、多くの場合、永続性を必要とする場合、このアルゴリズムはしません永続性を必要とする * IDが意味/リバーシブルあり:ID統計分析のアウトソリューションに対抗できるIDを、システム全体のカーブの非常に単純な分析することができビジー状態である、あなたはまた、すべてのマシンに移動することができます 、特定の時点での仕事は、ロードバランシングの状況を分析するために行われ、どのくらい 速く世代:*高性能を * * / パブリック クラスSnowflakeIdWorker { / ** 時間カットを開始(2019年8月21日)* / プライベート 最終 ロング = 1566316801000L twepoch ; / ** マシンIDがビット占有* / プライベート 最終 ロング workerIdBits = 5Lを; / ** 桁の識別データIDを共有* / プライベート 最終 ロング datacenterIdBits = 5L ; / ** 最大マシンIDによってサポートされる最大小数、結果は31である(このシフトアルゴリズムを迅速にいくつかの2進数を計算することができ表すことができます。数)* / プライベート 最終 ロング maxWorkerId -1L = ^(-1L << workerIdBits); / ** 最大データ識別ID、結果は31であります* / 民間 最終 ロング maxDatacenterId -1L = ^(-1L << datacenterIdBits); / ** 配列表すメジアンIDが* / プライベート 最終 ロング sequenceBits = 12L ; / ** 左にマシンID 12 * / プライベート ファイナル 長い workerIdShift = sequenceBits; / ** 17によって左(12 + 5)にIDを識別するデータ* / プライベート 最終 長い datacenterIdShift + = sequenceBits ; workerIdBits / ** 左22を切断する時間(5 + 5 + 12)* / プライベート 最終 ロング timestampLeftShift workerIdBits + + = sequenceBitsdatacenterIdBits; / ** マスクシーケンスを生成し、ここでは4095(0b111111111111 = 0xFFF = 4095)* / プライベート 最終 ロング sequenceMask -1L = ^(-1L << sequenceBits); / ** 作業機械のID(0〜31)* / プライベート ロングworkerId; / ** データセンターID(〜31が0である)* / プライベート ロングdatacenterId; / **は、シーケンス(0〜4095)ミリ秒* / プライベート ロングシーケンス= 0Lを; / ** 最後のIDが生成されますカットオフ時間* / プライベート ロング LastTimestamp = -1L ; / ** *コンストラクタ * @paramworkerId工作のID(〜31 0) * @param datacenterId数据ID(0〜31)中心 * / 公共 SnowflakeIdWorker(長い workerId、長いdatacenterId){ 場合(workerId> maxWorkerId || workerId <0 ){ スロー 新しい例外:IllegalArgumentException(文字列。フォーマット(「IDは、%D未満または0よりも大きくすることができない労働者」、maxWorkerId))。 } であれば(datacenterId> maxDatacenterId || datacenterId <0 ){ スロー 新しい、IllegalArgumentExceptionを(String.Formatのは、( "データセンターIdは%dまたは0より小さい値を超えることはできません"、maxDatacenterIdを)); .WorkerId = workerId; この .datacenterId = datacenterId; } / ** *(スレッドセーフである)次のIDを取得 * @return SnowflakeId * / パブリック 同期 ロングNEXTID(){ ロングタイムスタンプ= TIMEGEN(); / / 現在の時刻は、最後のタイムスタンプを介してスローされるべきシステムクロックバックオフ時間を示す、IDを生成未満の場合 IF(タイムスタンプ< LastTimestamp){ スロー 新しい新しいRuntimeExceptionは、( String.Formatのは、(「クロックが後退。IDを生成することを拒否するため%d個のミリ秒」、lastTimestamp -タイムスタンプ)); } // それが同時に発生した場合、配列はミリ秒以内に行われる IF(LastTimestamp == タイムスタンプ){ シーケンス =(+配列1)&sequenceMask; // ミリ秒シーケンスオーバーフロー IF(配列== 0 ) { // 新しいタイムスタンプの取得、次ミリ秒ブロッキング タイムスタンプ= ; tilNextMillis(LastTimestamp)を } } // タイムスタンプがミリ秒リセットシーケンス変更 他{ シーケンス = 0L ; } //を前回世代ID切り捨て = LastTimestampのタイムスタンプ; //シフトと論理和は、組成物64のIDと戦うために リターン((タイムスタンプ- twepoch)<< timestampLeftShift) LastTimestamp){ // |(DatacenterId << datacenterIdShift)// |(workerId << workerIdShift)// | シーケンス; } / ** 次のミリ秒*閉塞、新しいタイムスタンプまで * @param LastTimestamp時間は、以前に生成されたIDをカット * @return 現在のタイムスタンプ * / 保護 ロング tilNextMillis(ロングLastTimestamp){ ロングタイムスタンプ= TIMEGEN(); 一方、(タイムスタンプ<= タイムスタンプ = TIMEGEN(); } 戻り、タイムスタンプ } / ** *ミリ秒の現在時刻を返す * @return 現在の時間(ミリ秒) * / 保護 ロングTIMEGEN(){ 戻りのSystem.currentTimeMillisを(); } / ** テスト* / パブリック 静的 ボイドメイン(文字列[]引数){ SnowflakeIdWorker idWorker = 新しい新しい SnowflakeIdWorker(0、0 ); のため(int型 ; I 1000 <I ++はI = 0 ){ ロングID = idWorker.nextId()。 // のSystem.out.println(Long.toBinaryString(ID))。 System.out.println(ID)。 } / * 文字列S = "2019年8月21日午前0時00分01秒"。 長いTS = 0; SimpleDateFormatのSimpleDateFormat =新しいてSimpleDateFormat( "YYYY-MM-DD HH:MM:SS")。 試す{ 日付= simpleDateFormat.parse(S); TS = date.getTime()。 }キャッチ(例外e){ TS = 0。 } のSystem.out.println(TS)。* / } }