1

シングルトンパターンの例を実装しようとしています。質問の1つは、それぞれgetInstance()を呼び出す2つのスレッドを実行し、Singletonオブジェクトのインスタンスが1つだけ作成されたことを確認することです。

これが私のシングルトンコードです。

public class OurSingleton {

    static OurSingleton ourSingleton;
    static int instanceCounter;

    private OurSingleton(){
        instanceCounter++;
    }

    public static synchronized OurSingleton GetSingletonInstance(){

        if( ourSingleton == null){

            ourSingleton = new OurSingleton();

        }
        return ourSingleton;    
    }

    public static int getCounter() {

        return instanceCounter;

    }
}

そして私のメイン。

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {

        OurSingleton mySingleton = null;

        Thread one = new Thread(new GetSingletonInstance(mySingleton));
        Thread two = new Thread(new GetSingletonInstance(mySingleton));

        one.start();
        two.start();


        System.out.println("Main: " + mySingleton.getCounter());
    }   
}

class GetSingletonInstance implements Runnable {

    int count = 0;
    OurSingleton singleton;

    public GetSingletonInstance(OurSingleton ourSingleton){
        singleton = ourSingleton;
    }

    @Override
    public void run() {
        try {
            while (count < 5000000) {
                singleton.getSingletonInstance();
                count++;    
            }

        } catch (Exception e) {

            e.printStackTrace();
        }

        System.out.println("Thread: " + singleton.getCounter());

    }       
}

このコードを実行すると、次の出力が得られます。

メイン:0スレッド:1スレッド:1

誰かがこの出力の理由を説明できますか?全面的にシングルトンのインスタンスは1つしか存在しないと思いました。これは、別のオブジェクトがスレッドで作成されていることを意味しますか?アドバイスをいただければ幸いです。

4

7 に答える 7

8

メソッドの同期は避けるgetInstance必要があります(インスタンスが初期化された後、インスタンスを取得するためだけに不要なオーバーヘッドが発生するため)。シングルトンを遅延初期化するための推奨される方法は次のとおりです。

public class OurSingleton {

    private OurSingleton() { }

    public static OurSingleton getInstance() {
        return Holder.instance;
    }

    private static class Holder {
        private static OurSingleton instance = new OurSingleton();
    }        
}
于 2012-11-12T21:16:21.017 に答える
5

シングルトンの単一のインスタンスだけが全面的に存在すると考えました。これは、別のオブジェクトがスレッドで作成されていることを意味しますか?

JVMにはシングルトンのインスタンスが1つだけ存在します。各スレッドには、インスタンスが1つしかないという事実が表示されます。

Javaでシングルトンパターンを実装する最も簡単で安全な方法は、列挙型を使用することです。

public enum MySingleton {
    INSTANCE;

    public void doStuffHere() {
        //...
    }
}

public class ClientClass {
    public void myMethod() {
        MySingleton mySingleton = MySingleton.INSTANCE;
        mySingleton.doStuff();
    }
}

MySingletonのインスタンスは1つだけで、スレッドセーフです。

于 2012-11-12T21:37:43.963 に答える
4

同じクラスからスレッドの2つのインスタンスを作成しました。それぞれがシングルトンオブジェクトのインスタンスの数を出力します。数値は1です。これは、実際にインスタンスを1つだけ作成したため、シングルトンが正しく実装されていることを意味します。2つのスレッドを作成したため、これを2回印刷しました。

混乱を避けたい場合はSystem.out.println(...)、メインメソッドへの移動行。

于 2012-11-12T21:15:29.943 に答える
2

これをより良くする方法については、他の回答を見てください。なぜこの出力が得られるのかという質問があります。

Main: 0 
Thread: 1
Thread: 1

コードで

static int getInstanceCounter;

宣言を設定し、静的変数をゼロに設定しています。したがって、OurSingletonのインスタンスが作成される前は、getInstanceCounterの値はゼロです。電話するとき

System.out.println("Main: " + mySingleton.getCounter());

OurSignletonのインスタンスは作成されていないため、mySignleton.getCounter()はまだゼロです。

いずれかまたは両方のスレッドを実行すると、OurSingletonの1つのインスタンスが作成され、getInstanceCounterが1つになります。

シングルトンが機能しています。より良い方法は他の回答で言及されていますが。


余談ですが、あなたのコードに関するいくつかのことは、気難しいように見えるかもしれませんが、他の人があなたのコードを読むのに役立ちます。

  • 変数をプライベートにしてください

    static int getInstanceCounter; =>
    private static int getInstanceCounter;

  • 変数にはgetで名前を付けないでください

    private static int getInstanceCounter; =>
    private static int instanceCounter;

  • クラスのインスタンスで静的メソッドを参照しないでください

    mySingleton.getCounter()=>
    OurSingleton.getCount()

  • これは、値が割り当てられない変数mySingletonが参照されないようにし、削除する必要があることも意味します。

    public GetSingletonInstance(OurSingleton ourSingleton){
    singleton = ourSingleton;
    }
    =>
    public GetSingletonInstance(){
    singleton = OurSingleton.getInstance();
    }

于 2012-11-12T22:08:02.507 に答える
2

インスタンスは1つだけですOurSingletonが、クラスgetSingletonInstance(USE PROPER CAPS!)自体はシングルトンではありません。そして、それはあなたがカウンターを置くものです。

于 2012-11-12T21:12:29.077 に答える
2

私はこれをそう説明します:

クラスをロードするOurSingletonと、静的カウンターgetInstanceCounterはゼロに初期化されます。その後、クラスの新しいインスタンスを取得するたびに、カウンターは常に1になり、実際にシングルトンであることを示します。

次の変更を行うことをお勧めします

  1. シングルトンの静的変数をプライベートにします:ourSingletongetInstanceCounter
  2. 不要なオーバーヘッドがあるため、メソッドの同期キーワードを削除します
于 2012-11-12T21:26:11.580 に答える
0

(静的メンバー関数)OurSingleton.getInstanceCounterを介した(静的メンバー) へのアクセスは同期されません。OurSingleton.getCounter ()重要なのはそれだけです。プログラムの残りの部分は、単に物事を複雑にしているだけです。ポインタで静的関数を呼び出すmainことを介していることに注意してください!以外の値を持つことはありません。mySingleton.getCounter ()nullmySingletonnull

シングルトンパターンを実装するために使用enumするか、少なくとも1つの静的変数、つまりシングルトンオブジェクトを保持する変数のみを使用する必要があります。

于 2012-11-12T21:24:26.583 に答える