実際、プログラマーがコードを書くときに考慮する必要のある問題はたくさんあります。
-
可用性(ビジネス目標を完全に達成)
-
堅牢性(プログラムは、さまざまな環境およびさまざまな操作での通常の操作を保証できます)
-
再利用性(コードは他のモジュールから呼び出すことができ、さまざまな目的を達成できます。これは、ある程度デカップリングするという考え方です)
-
スケーラビリティ(コード設計は、できるだけ多くのビジネスに適応するのに十分な柔軟性があります)
-
パフォーマンス
- メモリフットプリント(私の理解では、パフォーマンスとメモリフットプリントはしばしばジレンマであり、パフォーマンスの向上は多くの場合、メモリ使用量の増加を意味します。たとえば、動的アレイArrayListは、頻繁な拡張を回避するために1.5倍に拡張されるため、データのコストが低くなります。増加する。)
上記の問題とコードの継続的な設計に基づいて、前任者はいくつかの一般的および一般的な問題に対応する最適な解決策を見つけました(これは問題の答えではなく問題を解決する方法であることに注意してください、それはより多くのことを意味します一種の考えであり、私たちのコードはこの考えのキャリアです)これから、デザインパターンが導き出されます:デザインパターン-シングルトンパターン。
01シングルトンの定義
シングルトンは単一のインスタンスです。Javaでは、これはクラスのオブジェクトが1つだけ存在できることを意味します。
なぜシングルトンが必要なのですか?私と一緒に考えてみてください。実際には、一人の買い物ニーズを満たすショッピングモールを建設することは不可能です。そして、モールは多くの人に物を売る機能を果たすことができ、その人は他の人のように物を売る機能を使うためにモールに入るだけです。
そのため、私たち全員が同じ目標を達成したわけではないことがわかりました。多くの場合、必要なのはそれ自体ではなく、それができることです。私は買い物用のモールを作るのではなく、他の人と同じモールで物を売る機能を使います。
同じことがjavaにも当てはまります。オブジェクトメソッドを使用します。必要なものは次のとおりです。
1.最初にこのオブジェクトを作成します
2.このオブジェクトメソッドを呼び出します
3.オブジェクトを破棄します
一人でも大丈夫なので、何千万人もいるとしたら?それは何百万回もオブジェクトを作成する必要がありますか?しかし、私たちの目標を達成するために何百万人もの人々が本当に必要としているのは、このオブジェクトではなく、このオブジェクトの機能です。
概要:メモリリソースの浪費や頻繁なオブジェクトの作成を回避するために、機能クラスが複数のオブジェクトで共有されている場合。このクラスは単調にする必要があります。
02シングルトン設計プロセス
コンストラクターの民営化
メモリ内に永久にオブジェクトが1つしかないことを保証するために、他のクラスにオブジェクトを作成させないでください。作成する権限を設定する必要があります。オブジェクトを作成する権限があるのはクラス自体だけです。
プライベートSingleTon(){}
内部で作成されたオブジェクト
現時点での問題は、クラス自体だけがオブジェクトを作成できる場合、どこにオブジェクトを作成する必要があるかということです。クラス構造(構築メソッド、コードブロック、メソッド、および属性)を確認してみましょう。
-
構築方法:内部メソッドが新しいオブジェクトであっても、構築メソッドはプライベート化されています。しかし、外の世界が実行構築メソッドを呼び出すことができないことを残念に思います、この新しいは実行できません
-
コードブロック:クラスの初期化時にコードブロックを実行できますが、問題は、卵を接続するバスケットがなく、このコードブロックで作成されたオブジェクトを見つけるためのアドレスを外部が取得できないことです。
-
方法:これは、最初に鶏肉か卵子かという問題です。この方法は、外部オブジェクトの作成には使用されません。
- 属性:オブジェクトも属性で作成できるかのように、これは最後のストローのようです
private SingleTon(){} public SingleTon singleTon = new SingleTon();
作成して取得
しかし、ここで問題が発生します。オブジェクトを作成し、オブジェクトのプロパティがオブジェクトを作成し、オブジェクトのプロパティがオブジェクトのプロパティを作成します。システムはそのような人形を実行します。
ヒープメモリ内のオブジェクトは引き続き属性をネストし、スタックメモリ内の最初のオブジェクトによって開かれた構築メソッドスタックはまだ実行されていないため、新しい構築メソッドスタックを開く必要があります。これにより、ヒープメモリ内のメソッドスタックが蓄積され続けてスタックが形成されます。メモリエスケープエラー。
このオブジェクトに必要なのは1つだけであり、静的領域にはクラスのオブジェクトが1つしか存在できないことをコンピューターに通知する必要があります。
この属性に静的修飾子を追加する必要があります。1つは、人形のようなオブジェクトの作成を回避するために他のクラスの初期化を完了することです。もう1つは、静的変数を外部から取得できることです。
しかし、現時点では別の問題があります。
SingleTon.singleTon = null
ユーザーがこのユニークなオブジェクトを改ざんした場合、それは実現不可能です。簡単なパッケージを作成し、バックドアだけを残してそれを取得する必要があります。
private SingleTon(){} private static SingleTon singleTon = new SingleTon(); public static SingleTon getSingleTon(){return singleTon; }
ただし、Javaの世界では、オープンにできることを忘れないでください。改ざんのリフレクションを通じてプライベート属性を取得できるため、変数自体を完全に変更できないように最終的な変更を追加する必要があります。
方法1:
private SingleTon(){} private static final SingleTon singleTon = new SingleTon(); public static SingleTon getSingleTon(){return singleTon; }
これはシングルトンメソッドの1つであり、このコードには問題があります。私のビジネスが実行されるとき、私はこのオブジェクトを使用しないかもしれませんが、このオブジェクトは初期化後にメモリ内でコールドです。システムに数千万のシングルトンがある場合、システムが初期化されると、それに応じてすべてのシングルトンオブジェクトが初期化されます。サーバーのプレッシャーは想像しがたいものです。
したがって、メカニズムを設定し、必要なときに作成できます。このとき、みんなから質問がありました。マルチスレッドだとどうなりますか?
方法2:
private SingleTon(){} private static SingleTon singleTon; public static SingleTon getSingleTon(){if(singleTon == null){singleTon = new SingleTon(); }}
ABが2つのスレッドがある場合:通常、AはAが作成されていないと判断し、Aが作成され、Bが直接使用されていると判断します。
しかし、Aの作成時にオブジェクトが作成されていないことをBが検出した場合はどうなりますか
これは、マルチスレッドの同時実行性に達しないアトミック性によって引き起こされるセキュリティの問題です
そのため、マルチスレッドによる問題を防ぐために、メソッドにロックを追加する必要があります。ロック期間中は、他のスレッドはメソッドを使用できません。
方法3:
//高高PprivateSingleTon(){} private static SingleTon singleTon; public static synchronized SingleTon getSingleTon(){if(singleTon == null){SingleTon = new singleTon(); }}
しかし、別の問題があります。このメソッドは他の多くのことを内部で実行し、これらのマルチスレッド環境は問題を引き起こしません。
このとき、他のスレッドは不必要に長時間待機するため、ローカルでロックする必要があります(スレッドが長時間ロックを保持しないように最善を尽くす必要があります)
方法4:
private SingleTon(){} private static SingleTon singleTon; public static SingleTon getSingleTon(){if(singleTon == null){synchronized(Singleton.class){//判断の直後にこのクラスをロックします//前のロックを防ぐため誰かが最初にオブジェクトを作成してから、別の判断を下しますif(singleTon == null){singleTon = new Singleton()}}}}
現時点で、実際には最後の質問が1つあります。
single = new Singleton();このコード行は、3つのステップに分割された複数のステップを実行しました
-
メモリスペースを割り当てる
-
コンストラクターを呼び出し、オブジェクトをロードします
- 変数にアドレスを割り当てる
現時点では、jvm自体に命令再配置の機能があります。つまり、これら3つの命令をシャッフルして実行することができます。パフォーマンスを向上させるために、コンパイラとプロセッサは、確立されたコードの実行順序を再配置することがよくあります。
現時点では、誰もが私と一緒に考えています。1が実行されると、3が最初に実行されます。3を実行して2を実行する準備をする前に、別のスレッドがこの変数にアドレス参照があると判断します。空でないものを使用したところ、使用したところ、空のシェルであることがわかり、nullポインタ例外が発生していました。
したがって、jvmで命令の再配置を実行しないようにする必要があります。Javaは変数を変更するためにvolatileキーワードvolatileを提供します。2つの特徴があります。1。命令の再配置を禁止する2.変数の可視性を確保する最初の機能は、命令の再配置の問題を解決するのに役立ちます。
方法5:
private SingleTon(){} private static volatile SingleTon singleTon; public static SingleTon getSingleTon(){if(singleTon == null){synchronized(Singleton.class){if(singleTon == null){singleTon = new Singleton()}} }}
総括する:
方法1:属性にオブジェクトを作成します。静的な変更は、構築メソッドの複数の実行を防ぎ、変更を防ぐためのプライベートな変更を行います。
方法2:遅延読み込みメカニズムを追加し、必要に応じて、オブジェクトが再度作成されない場合
方法3:高い同時実行性を防ぐために、メソッドをロックします
方法4:ローカルロックは割り当てプロセスにのみ使用されます。方法5揮発性の変更された変数は命令の再配置を防ぎます
この記事はオリジナルです
著者:ヤン