コンセプト:
JavaのSingletonパターンは、一般的なデザインパターンです。シングルトンパターンは、レイジーシングルトン、ハングリーシングルトン、登録されたシングルトンの3つのタイプに分かれています。
Singletonモードには次の特性があります。
1.シングルトンクラスには1つのインスタンスしかありません。
2。シングルトンクラスは、独自のユニークなインスタンスを作成する必要があります。
3. Singletonクラスは、他のすべてのオブジェクトにこのインスタンスを提供する必要があります。
Singleton Patternは、クラスに1つのインスタンスしかないことを保証し、それ自体をインスタンス化し、このインスタンスをシステム全体に提供します。コンピューターシステムでは、スレッドプール、キャッシュ、ログオブジェクト、ダイアログボックス、プリンター、グラフィックカード用のドライバーオブジェクトは、多くの場合、シングルトンとして設計されています。これらのアプリケーションには、多かれ少なかれリソースマネージャーの機能があります。各コンピューターには複数のプリンターを使用できますが、プリンタースプーラーが1つだけ使用できるのは、2つの印刷ジョブが同時に出力されないようにすることができます。各コンピューターにはいくつかの通信ポートがあり、システムはこれらの通信ポートを中央に管理して、1つの通信ポートが2つのリクエストによって同時に呼び出されないようにする必要があります。要するに、シングルトンモデルを選択することは、一貫性のない状態を避け、政治的な強気を避けることです。
ここに2種類の紹介があります:怠zyと空腹
1.すぐにロード/空腹のスタイル
メソッドを呼び出す前に、インスタンスが作成されました、コード:
パッケージcom.weishiyao.learn.day8.singleton.ep1; public class myobject {// loading now == evil mode private static myobject = new Myobject(); private myobject(){} public static myobject getInstance(){// }}スレッドクラスを作成します
パッケージcom.weishiyao.learn.day8.singleton.ep1; public class mythread extends thread {@override public void run(){system.out.println(myobject.getInstance()。hashcode()); }}実行クラスを作成します
パッケージcom.weishiyao.learn.day8.singleton.ep1; public class run {public static void main(string [] args){mythread t1 = new Mythread(); mythread t2 = new mythread(); mythread t3 = new mythread(); t1.start(); t2.start(); t3.Start(); }}実行結果
167772895
167772895
167772895
ハッシュコードは同じ値です。つまり、オブジェクトも同じであることを意味します。つまり、インスタントロードモードが実装されています。
2。怠zyなロード/怠zy
インスタンスは、メソッドが呼び出された後に作成されます。実装計画は、オブジェクトのインスタンスがメソッドが呼び出された場合にのみ作成されるように、パラメーターのないコンストラクターにインスタンス化することです。コード:
パッケージcom.weishiyao.learn.day8.singleton.ep2; public class myobject {private static myobject myobject; private myobject(){} public static myobject getInstance(){// if(myobject!= null){} else {myobject = new Myobject(); } myobjectを返します。 }}スレッドクラスを作成します
パッケージcom.weishiyao.learn.day8.singleton.ep2; public class mythread extends thread {@override public void run(){system.out.println(myobject.getInstance()。hashcode()); }}実行クラスを作成します
パッケージcom.weishiyao.learn.day8.singleton.ep2; public class run {public static void main(string [] args){mythread t1 = new Mythread(); t1.start(); }}実行結果
167772895
オブジェクトのインスタンスは撮影されますが、マルチスレッド環境にある場合、複数のインスタンスが発生しますが、これはシングルトンパターンではありません。
テストクラスを実行します
パッケージcom.weishiyao.learn.day8.singleton.ep2; public class run {public static void main(string [] args){mythread t1 = new Mythread(); mythread t2 = new mythread(); mythread t3 = new mythread(); mythread t4 = new mythread(); mythread t5 = new mythread(); t1.start(); t2.start(); t3.Start(); t4.start(); t5.Start(); }}実行結果
980258163
1224717057
1851889404
188820504
1672864109
問題があるので、問題を解決する必要があります。レイジーモードのマルチスレッドソリューション、コード:
最も一般的には、最初のソリューションは同期を追加し、同期して異なる位置に追加できます
最初の方法はロックされます
パッケージcom.weishiyao.learn.day8.singleton.ep3; public class myobject {private static myobject myobject; private myobject(){}同期public static myobject getInstance(){// [Delay Loading try {if(myobject!= null){} else {//オブジェクトスレッドを作成する前に準備をシミュレートします。 myobject = new Myobject(); }} catch(arturnedexception e){e.printstacktrace(); } myobjectを返します。 }}この同期化された同期スキームは、効率が強すぎて、メソッド全体がロックされています
2番目の同期使用スキーム
パッケージcom.weishiyao.learn.day8.singleton.ep3; public class myobject {private static myobject myobject; private myobject(){} public static myobject getInstance(){// delay roading try {synchronized(myobject.class){if(myobject!= null){} else {//オブジェクトスレッドを作成する前に準備作業をシミュレートする前に、sleap(2000); myobject = new Myobject(); }}} catch(arturnedexception e){e.printstacktrace(); } myobjectを返します。 }}この方法も非常に低い効率です。メソッド内のすべてのコードがロックされています。キーコードをロックするだけです。 3番目の同期使用計画
パッケージcom.weishiyao.learn.day8.singleton.ep3;
public class myobject {private static myobject myobject; private myobject(){} public static myobject getInstance(){// [遅延ロード] try {if(myobject!= null){} else {//オブジェクトスレッドを作成する前にいくつかの準備をシミュレートします。同期(myobject.class){myobject = new Myobject(); }}} catch(arturnedexception e){e.printstacktrace(); } myobjectを返します。 }}これは最良の解決策のようですが、それを実行した後、私はそれが実際には非スレッドセーフであることがわかりました
結果:
1224717057
971173439
1851889404
1224717057
1672864109
なぜ?
オブジェクトを作成するステートメントはロックされていますが、最初のスレッドがオブジェクトオブジェクトを作成するために作成された後、1つのスレッドのみが作成を完了することができますが、2番目のスレッドは作成され続けることができます。
パッケージcom.weishiyao.learn.day8.singleton.ep3; public class myobject {private static myobject myobject; private myobject(){} public static myobject getInstance(){// [遅延]トライ{if(myobject!= null){} else {//オブジェクトスレッドを作成する前にいくつかの準備をシミュレートします。同期(myobject.class){if(myobject == null){myobject = new Myobject(); }}}} catch(arturnedexception e){e.printstacktrace(); } myobjectを返します。 }}シングルトンを確保するために、ロックに別の判断を追加するだけです。これはDCLの再チェックメカニズムです
結果は次のとおりです。
1224717057
1224717057
1224717057
1224717057
1224717057
3.組み込みの静的クラスを使用して、単一のケースを実装します
メインコード
パッケージcom.weishiyao.learn.day8.singleton.ep4; public class myobject {// inner class method private static class myobjecthandler {private static myobject myobject = new Myobject(); } public myobject(){} public static myobject getInstance(){return myobjecthandler.myobject; }}スレッドクラスコード
パッケージcom.weishiyao.learn.day8.singleton.ep4; public class mythread extends thread {@override public void run(){system.out.println(myobject.getInstance()。hashcode()); }}クラスを実行します
パッケージcom.weishiyao.learn.day8.singleton.ep4; public class run {public static void main(string [] args){mythread t1 = new mythread(); mythread t2 = new mythread(); mythread t3 = new mythread(); mythread t4 = new mythread(); mythread t5 = new mythread(); t1.start(); t2.start(); t3.Start(); t4.start(); t5.Start(); }}結果
1851889404
1851889404
1851889404
1851889404
1851889404
内部静的クラスを通じて、スレッドセーフシングルトンパターンが取得されます
IV。シングルトンのパターンをシリアル化して脱皮化します
組み込みの静的クラスは、スレッドの安全性の問題を実現できますが、シリアル化されたオブジェクトが発生した場合、デフォルトメソッドを使用して取得した結果は依然として複数のケースです。
myobjectコード
パッケージcom.weishiyao.learn.day8.singleton.ep5; import java.io.serializable; public class myobjectはserializable { / ** * * / private static final long serialversionuid = 888l; //内部クラスメソッドprivate static class myobjecthandler {private static myobject myobject = new Myobject(); } public myobject(){} public static myobject getInstance(){return myobjecthandler.myobject; } //保護されたmyobject readResolve(){// system.out.println( "readResolveメソッドは呼び出されました!");仕事
package com.weishiyao.learn.day8.singleton.ep5;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class saveandread {public static void main(string [] args){try {myobject myobject = myobject.getInstance(); fileoutputStream fosref = new fileoutputStream(new File( "MyobjectFile.txt")); ObjectOutputStream oosRef = new objectOutputStream(fosref); oosref.writeobject(myobject); oosref.close(); fosref.close(); system.out.println(myobject.hashcode()); } catch(filenotfoundexception e){e.printstacktrace(); } catch(ioexception e){e.printstacktrace(); } fileInputStream fisref; try {fisref = new fileInputStream(new file( "myobjectfile.txt")); ObjectInputStream iOSREF = new ObjectInputStream(fisref); myobject myobject =(myobject)iosref.readobject(); iOSREF.CLOSE(); fisref.close(); system.out.println(myobject.hashcode()); } catch(filenotfoundexception e){e.printstacktrace(); } catch(ioexception e){e.printstacktrace(); } catch(classNotFoundException e){e.printstacktrace(); }}}結果
970928725
1099149023
2つの異なるハッシュコードは、それらが同じオブジェクトではないことを証明しています。解決策、次のコードを追加します
保護されたmyobject readResolve(){system.out.println( "readResolveメソッドが呼び出されました!"); myobjecthandler.myobjectを返します。 }脱介入中に呼び出されると、同じオブジェクトを取得できます
system.out.println(myobject.readResolve()。hashcode());
結果
1255301379
ReadResolveメソッドが呼び出されました!
1255301379
同じハッシュコードは、同じオブジェクトが取得されることを証明します
5.静的コードブロックを使用して、単一のケースを実装します
静的コードブロックのコードは、クラスを使用するときに既に実行されているため、静的コードの機能を使用して、単純な利益モードを実装できます。
myobjectクラス
パッケージcom.weishiyao.learn.day8.singleton.ep6; public class myobject {private static myobject instance = null; private myobject(){super(); } static {instance = new Myobject(); } public static myobject getInstance(){return instance; }}スレッドクラス
パッケージcom.weishiyao.learn.day8.singleton.ep6; public class mythread extends thread {@override public void run(){for(int i = 0; i <5; i ++){system.out.println(myobject.getinstance()。hashcode()); }}}クラスを実行します
パッケージcom.weishiyao.learn.day8.singleton.ep6; public class run {public static void main(string [] args){mythread t1 = new Mythread(); mythread t2 = new mythread(); mythread t3 = new mythread(); mythread t4 = new mythread(); mythread t5 = new mythread(); t1.start(); t2.start(); t3.Start(); t4.start(); t5.Start(); }}実行結果:
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
167885403
スレッドセーフシングルトンパターンは、静的コードブロックを1回だけ実行する機能によって正常に取得されます。
6.列挙列挙データ型を使用して、シングルトンモードを実装する
Enum Enumと静的コードブロックの特性は類似しています。 enumsを使用する場合、コンストラクターは自動的に呼び出され、Singletonモードを実装するためにも使用できます。
myobjectクラス
パッケージcom.weishiyao.learn.day8.singleton.ep7; import java.sql.connection; import java.sql.drivermanager; import java.sql.sqlecception; public enum myobject {connectionfactory;プライベート接続接続。 private myobject(){try {system.out.println( "myobjectの構成要素が呼ばれた"); string url = "jdbc:mysql://172.16.221.19:3306/wechat_1?useunicode = true&charatereCoding = utf-8";文字列name = "root";文字列パスワード= "111111"; string drivername = "com.mysql.jdbc.driver"; class.forname(drivername); connection = drivermanager.getConnection(url、name、password); } catch(classNotFoundException e){e.printstacktrace(); } catch(sqlexception e){e.printstacktrace(); }} public connection getConnection(){return connection; }}スレッドクラス
パッケージcom.weishiyao.learn.day8.singleton.ep7; public class mythread extends thread {@override public void run(){for(int i = 0; i <5; i ++){system.out.print.println(myobject.connectionfactory.getConnection()。ハスコード()。 }}}クラスを実行します
パッケージcom.weishiyao.learn.day8.singleton.ep7; public class run {public static void main(string [] args){mythread t1 = new Mythread(); mythread t2 = new mythread(); mythread t3 = new mythread(); mythread t4 = new mythread(); mythread t5 = new mythread(); t1.start(); t2.start(); t3.Start(); t4.start(); t5.Start(); }}実行結果
myobject constructと呼ばれます
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
56823666
上記の執筆方法は、「単一の責任原則」に違反する列挙クラスを公開します。クラスを使用して列挙をラップできます。
パッケージcom.weishiyao.learn.day8.singleton.ep8; import java.sql.connection; import java.sql.drivermanager; import java.sql.sqlecception; public class myobject {public enum myenumsingleton {connectionfactory;プライベート接続接続。 private myenumsingleton(){try {system.out.println( "myobjectの構成要素が呼び出されました"); string url = "jdbc:mysql://172.16.221.19:3306/wechat_1?useunicode = true&charatereCoding = utf-8";文字列name = "root";文字列パスワード= "111111"; string drivername = "com.mysql.jdbc.driver"; class.forname(drivername); connection = drivermanager.getConnection(url、name、password); } catch(classNotFoundException e){e.printstacktrace(); } catch(sqlexception e){e.printstacktrace(); }} public connection getConnection(){return connection; }} public static Connection getConnection(){return myenumsIngleton.ConnectionFactory.getConnection(); }}スレッドコードを変更します
パッケージcom.weishiyao.learn.day8.singleton.ep8; public class mythread extends thread {@override public void run(){for(int i = 0; i <5; i ++){system.out.println(myobject.getConnection()。hashcode()); }}}その結果、Myobjectコンストラクトが呼び出されます
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
1948356121
上記は、シングルインテストモードとマルチスレッドを組み合わせるときに遭遇するさまざまな状況とソリューションをまとめたもので、後で使用するとレビューできます。