マルチスレッドでシングルトンスレッドの安全性を確保する方法
ビッグデータの知識、分散、高い同時実行は、基礎をスレッド化する方法を学ぶ必要があります。ここではマルチスレッドの場合はシングルトンの設計方法について話をします。23のデザインパターンではSingletonパターンは、非マルチスレッドの場合にシングルトンを書き、それを考慮することは非常にいくつかのことになりますが、一緒にマルチスレッドとシングルケースモデルならば、物事は変更を検討し、より一般的ですより、不適切に使用されている場合(特にビルド環境では)深刻な結果になります。それでは、どのように安全なシングルトンパターンは、複数のスレッドで特に重要であるが、ここではそれぞれのアプローチと可用性の長所と短所は以下のとおりです。
1.ロード直後に(飢えモード)
負荷モードはすぐのgetInstance()メソッドを呼び出す前に、インスタンスは、例えば、作成されています。
MyObjectにクラス{パブリック
//負荷直ちに実施の形態==飢え
プライベート新しい新しい静的MyObjectにはMyObjectにmyObjectという=();
プライベートMyObjectに(){
}
パブリック静的MyObjectにのgetInstance(){
myObjectというを返します;
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは、Thread {拡張し
ます。public void実行を(){
System.out.printlnは(。MyObject.getInstance()のhashCode());
}
}
-------------------------------------------------- ----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
MyThread T2 =新しいMyThread()。
MyThread T3 =新しいMyThread();
t1.start();
t2.start();
t3.start();
}
}
印刷コンソール:
714682869
714682869
714682869
同じハッシュコードアウト3枚のコンソールプリントは、1つのオブジェクトだけが直ちにロードされ、シングルトンであり、記載されています。このモデルは、欠点を有している、しかし、そこのgetInstance()メソッドが同期されていないため、他のインスタンス変数ではないので、発生する可能性があり、非スレッド安全性の問題ということです。
2.負荷遅延(遅延モード)
遅延ロードは、インスタンスを作成するために、実施例のgetInstance()メソッドです。
パブリッククラスMyObjectに{
プライベート静的MyObjectにmyObjectという。
プライベートMyObjectに(){
}
パブリック静的MyObjectにのgetInstance(){
//延迟加载
場合(myObjectという= nullを!){
}他{
myObjectという=新しいMyObjectに();
}
戻りmyObjectという。
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは、Thread {拡張し
ます。public void実行を(){
System.out.printlnは(。MyObject.getInstance()のhashCode());
}
}
-------------------------------------------------- -----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
t1.start();
}
}
印刷コンソール:
1701381926
コンソールの一例は、プリントアウト。短所:複数のインスタンスがSingletonパターンがずれ意図して、撮影されますマルチスレッド環境では。そのため、マルチスレッド環境では、このサンプルコードは間違っています。
前記遅延同期読み込みを修正する方法
パブリッククラスMyObjectに{
プライベート静的MyObjectにmyObjectという。
プライベートMyObjectに(){
}
同期のpublic static MyObjectにのgetInstance(){
{みてください
(myObjectという= nullを!){場合
}他{
のThread.sleep(3000);
myObjectという=新しいMyObjectに();
}
}キャッチ(InterruptedExceptionある電子){
// TODO:例外処理
e.printStackTraceを();
}
戻りmyObjectという。
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは、Thread {拡張し
ます。public void実行を(){
System.out.printlnは(。MyObject.getInstance()のhashCode());
}
}
-------------------------------------------------- -----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
MyThread T2 =新しいMyThread()。
MyThread T3 =新しいMyThread();
t1.start();
t2.start();
t3.start();
}
}
印刷コンソール:
1069480624
1069480624
1069480624
同じ例を得たが、我々は同期が同期している知っているが、スレッドが効率に影響を与え、ロックの解除後に実行する別のスレッドを待たなければなりません。
4.同期コードブロックの遅延ローディング、クラスのロックを使用
パブリッククラスMyObjectに{
プライベート静的MyObjectにmyObjectという。
プライベートMyObjectに(){
}
パブリック静的MyObjectにのgetInstance(){
しようと{
同期(MyObject.class){
場合(myObjectという= nullを!){
}他{
のThread.sleep(3000);
myObjectという=新しいMyObjectに();
}
}
}キャッチ(InterruptedExceptionある電子){
// TODO:ハンドル例外
e.printStackTrace();
}
戻りmyObjectという。
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは、Thread {拡張し
ます。public void実行を(){
System.out.printlnは(。MyObject.getInstance()のhashCode());
}
}
-------------------------------------------------- -----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
MyThread T2 =新しいMyThread()。
MyThread T3 =新しいMyThread();
t1.start();
t2.start();
t3.start();
}
}
印刷コンソール:
1743911840
1743911840
1743911840
このコードは正確であるが、コード内のgetInstance()メソッドも、実際には、第三の方法で同期され、同じ効率を低下させるであろうが
5. DCLダブルチェックロック機構
揮発性キーワードロック機構の使用(変数が複数のスレッドに表示されている)と、オブジェクト同期コードブロックの変形そのDCLダブルチェック
パブリッククラスMyObjectに{
プライベート揮発性の静的MyObjectにmyObjectという。
プライベートMyObjectに(){
}
パブリック静的MyObjectにのgetInstance(){
しようと{
場合(myObjectという= nullを!){
}他{
のThread.sleep(3000);
同期(MyObject.class){
IF(myObjectという== NULL){
myObjectという=新しいMyObjectに()。
}
}
}
}キャッチ(InterruptedExceptionある電子){
e.printStackTrace();
// TODO:例外を処理
}
myObjectというを返します。
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは、Thread {拡張し
ます。public void実行を(){
System.out.printlnは(。MyObject.getInstance()のhashCode());
}
}
-------------------------------------------------- -----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
MyThread T2 =新しいMyThread()。
MyThread T3 =新しいMyThread();
t1.start();
t2.start();
t3.start();
}
}
印刷コンソール:
798941612
798941612
798941612
ロック機構をチェックダブルDCLを使用して、成功したマルチスレッドの遅延ロードパターンは、スレッドセーフを達成遭遇する問題を解決しました。実際には、DCLほとんどのマルチスレッドシングルトンパターンの例を組み合わせて使用することは良い解決策です。
6.ビルトインクラスは、静的なシングルトンを使用して実装しました
パブリッククラスMyObjectに{
//内部类方式
プライベート静的クラスMyObjectHandler {
プライベート静的MyObjectにmyObjectという=新しいMyObjectに();
}
プライベートMyObjectに(){
}
パブリック静的MyObjectにのgetInstance(){
リターンMyObjectHandler.myObject。
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは、Thread {拡張し
ます。public void実行を(){
System.out.printlnは(。MyObject.getInstance()のhashCode());
}
}
-------------------------------------------------- -----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
MyThread T2 =新しいMyThread()。
MyThread T3 =新しいMyThread();
t1.start();
t2.start();
t3.start();
}
}
印刷コンソール:
1743911840
1743911840
1743911840
ビルトインクラスは、静的なマルチスレッドモードを使用して解決することができる、非スレッドセーフ問題の単一のケースとは、スレッドセーフを実現するが、オブジェクトのシリアル化された場合に所望の効果を達成することができません。
7.シリアライズとデシリアライズシングルトン
メソッドははreadResolveが必要
パブリッククラスMyObjectにはSerializable {実装
プライベート静的最終長いserialVersionUIDの= 888Lを。
//内部类
プライベート静的クラスMyObjectHandler {
プライベート静的最終MyObjectにmyObjectという=新しいMyObjectに()。
}
プライベートMyObjectに(){
}
パブリック静的MyObjectにのgetInstance(){
リターンMyObjectHandler.myObject。
}
保護オブジェクトはreadResolve()はObjectStreamException {スロー
するSystem.out.println( "调用了はreadResolve方法"を参照)。
MyObjectHandler.myObjectを返します。
}
}
-------------------------------------------------- -----------------
パブリッククラスSaveAndRead {
パブリック静的無効メイン(文字列[] args){
{試みる
MyObjectにmyObjectという= MyObject.getInstance()。
FileOutputStream fosRef =新しいのFileOutputStream(新しいファイル( "myObjectFile.txt"));
ObjectOutputStreamのoosRef =新しいObjectOutputStreamの(fosRef)。
oosRef.writeObject(myObjectという)。
oosRef.close();
fosRef.close();
System.out.println(myObject.hashCode())。
}キャッチ(にFileNotFoundException電子){
// TODO:例外を処理
}キャッチ(IOExceptionを電子){
e.printStackTrace();
}
{試みる
FileInputStreamのfisRef =新しいFileInputStreamを(新しいファイル( "myObjectFile.txt"));
ObjectInputStreamのiosRef =新しいObjectInputStreamの(fisRef)。
MyObjectにmyObjectという=(MyObjectに)iosRef.readObject();
iosRef.close();
fisRef.close();
System.out.println(myObject.hashCode())。
}キャッチ(にFileNotFoundException電子){
// TODO:例外を処理
}キャッチ(IOExceptionを電子){
e.printStackTrace();
}キャッチ(ClassNotFoundExceptionが電子){
e.printStackTrace();
}
}
}
印刷コンソール:
1988716027
コールreadResolveメソッド
1988716027
readResolveの道を呼び出した後、一つのケースであり、我々はreadResolveメソッドをコメントしている場合
印刷コンソール:
977199748
536468534
8.静的ブロックシングルトンを使用して実装しました
パブリッククラスMyObjectに{
プライベート静的MyObjectにインスタンス= NULL;
プライベートMyObjectに(){
}
静的{
インスタンス=新しいMyObjectに()。
}
パブリック静的MyObjectにのgetInstance(){
インスタンスを返します。
}
}
-------------------------------------------------- -----------------
パブリッククラスMyThreadは{スレッドを拡張します
ます。public void実行(){
のために(int型私= 0;私は<5; I ++){
System.out.printlnは(MyObject.getInstance()のhashCode());
}
}
}
-------------------------------------------------- -----------------
パブリッククラス実行{
パブリック静的無効メイン(文字列[] args){
MyThreadさt1 =新しいMyThread()。
MyThread T2 =新しいMyThread()。
MyThread T3 =新しいMyThread();
t1.start();
t2.start();
t3.start();
}
}
印刷コンソール:
798941612
798941612
798941612