空腹
飢えたスタイルのシングルトン実装は、クラスのロード時にクラスが作成および初期化されるため、インスタンス作成プロセスはスレッドセーフです
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private static final IdGenerator instance = new IdGenerator();
private IdGenerator(){}
public static IdGenerator getInstance(){
return instance;
}
public long getId(){
return id.incrementAndGet();
}
}
ただし、空腹な中国のスタイルには欠点があります。遅延ロードをサポートしていないため、インスタンスは使用前に作成されています。リソースを大量に消費しているのに使用していない場合、ある程度の無駄が発生します。特定の状況により、この方法を使用するかどうかが決まります。ただし、時間がかかる場合は、使用時にロードするとパフォーマンスに影響が出て、お腹がすいていると言う人もいます。
AtomicLongは、スレッドセーフなアトミック操作を提供するアトミック変数タイプです。これにより、マルチスレッド環境では、IDを取得するときに重複したIDが発生しなくなります。
コード内のコンストラクターはプライベート修飾子で装飾され、外部コードがコンストラクターを通じてIdGeneratorクラスを初期化できないようにします。
上記は、空腹の中国スタイルのシングルトン実装モードを使用した単純な一意の増分ID番号ジェネレーターであり、インスタンスインスタンスは静的定数として定義されています。クラスを実行するとき、最初にそれをJVMにロードする必要があることを知っています。ロードプロセスは3つのステージに分かれています。つまり、ロード、リンク、初期化です。リンクステージは、検証、準備、解決の3つのステップに分かれており、準備ステップでクラスまたはインターフェイスの静的が作成されます。変数と静的変数の初期値を初期化します。
怠惰な
上記で、空腹の中国スタイルは遅延ロードをサポートせず、遅延スタイルは遅延ロードをサポートし、遅延スタイルはインスタンスを取得するメソッドにロックを追加することで実装されます。
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private static IdGenerator instance;
private IdGenerator(){}
public static synchronized IdGenerator getInstance(){
if (instance == null){
instance = new IdGenerator();
}
return instance;
}
public long getId(){
return id.incrementAndGet();
}
}
ロックの結果、パフォーマンスが低下します。このシングルトンが頻繁に使用される場合、パフォーマンスの問題はより深刻になるため、それを実現する別の方法を検討する必要があります。
二重検出
二重検出の単一インスタンス実装方法は、上記の空腹で遅延のあるスタイルの欠点、つまり読み込みの遅延と低パフォーマンスの問題を補います。具体的な実装方法は、インスタンスを取得する前に作成されたかどうかを判断することです。直接の戻り、これが最初の検出であり、そうでない場合は、同期ブロックに入り、同期ブロックに入り、インスタンスがすでに存在するかどうかを判断し、存在する場合は直接戻り、2番目の検出で、存在しない場合は同期します。インスタンスを作成します。
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private static IdGenerator instance;
private IdGenerator(){
// 初始化代码
}
public static IdGenerator getInstance(){
if (instance == null){
synchronized (IdGenerator.class){ // 这里指明synchronized保护的是当前的类对象
if (instance == null){
instance = new IdGenerator();
}
}
}
return instance;
}
public long getId(){
return id.incrementAndGet();
}
}
遅延実装メソッドは、インスタンスが取得されるたびに同期コードを入力する必要があります。これにより、複数の取得ロックによってロックが解除され、パフォーマンスが低下しますが、実際には、二重検出でインスタンスの作成を一度同期するだけで取得できます。インスタンスに同期ブロックコードを入力する必要がないため、パフォーマンスが大幅に向上します。
静的内部クラス
静的内部クラスの実装は、二重検出よりも単純な実装であり、パフォーマンスと遅延読み込みの両方を保証します。
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private IdGenerator(){
// 初始化代码
}
private static class SingletonHolder{
private static final IdGenerator instance = new IdGenerator();
}
public static IdGenerator getInstance(){
return SingletonHolder.instance;
}
public long getId(){
return id.incrementAndGet();
}
}
SingletonHolderは静的な内部クラスです。privatを使用すると、内部クラスを外部の世界から完全に隠すことができます。外部クラスIdGeneratorが読み込まれると、インスタンスは作成されません。getInstanceメソッドが呼び出されたときにのみ、SingletonHolderが読み込まれ、インスタンスが作成されます。空腹スタイルのセキュリティ機能に加えて、遅延読み込みの機能もあります。
列挙
列挙型の実装は、Java列挙型自体の特性を使用して、インスタンス作成のスレッドセーフとインスタンスの一意性を保証することです。
public enum IdGenerator {
INSTANCE;
private AtomicLong id = new AtomicLong(0);
public long getId(){
return id.incrementAndGet();
}
public static void main(String[] args) {
IdGeneratorEnum.INSTANCE.getId();
}
}
列挙の実装が最も簡潔であり、jvmがスレッドの安全性と単一のインスタンスを保証することがわかります。また、シリアライゼーションとデシリアライゼーションが複数のインスタンスを作成したり、リフレクションを使用して複数のインスタンスを作成したりすることも効果的に防止できます。列挙型をクラスファイルにコンパイルし、逆コンパイルした後、
public final class IdGenerator extends java.lang.Enum<IdGenerator> {
public static final IdGenerator INSTANCE;
public static IdGenerator[] values();
public static IdGenerator valueOf(java.lang.String);
public long getId();
public static void main(java.lang.String[]);
static {};
}
逆コンパイルされた列挙型クラスは、実際にはEnumクラスを継承します。INSTANCEは静的定数です。空腹なHan型に戻っているようですが、読み込みが遅延しており、機能が簡潔です
ようこそ誰も私のブログシュシュ、戦闘ああのテストについての詳細があります!!