55

シングルトンオブジェクトにアクセスし、そのメソッドを呼び出してオブジェクトを渡す複数のスレッドが実行されています。メソッドでは、受信したオブジェクトに対してのみいくつかの計算を行います。この場合、ステートレスであり、すべて無料であるため、問題はないと聞いています。

私の質問は、どのようにすべての人にとって無料なのですか? 他のスレッドの渡されたオブジェクトを上書きすることなく、複数のスレッドが独自のスレッドで共有メソッドを呼び出す方法を知りたいですか? メモリ割り当てに関して、およびスタックレベルで説明してください。

class Singleton class{

    //no shared class or object variables and only one copy of this Singleton object exists.

    Object someMethod(Object o){
        //do some calculation or logic on the object o and return some string result
    }

}
4

4 に答える 4

76

すでにメモリに保存したものとコードの実行を区別する必要があると思います。

シングルトン オブジェクトには次のものがあります。

  • フィールド: それらはメモリに保存されます。それらは複数のスレッド間で共有でき、一貫性を保つ保証はありません (同期化しない限り)。
  • 呼び出されるメソッド: 複数のスレッドから呼び出すことができます。共有フィールドに不適切にアクセスしない限り、各実行は独立しており、スレッドセーフです。

あなたの質問に来てください:シングルトンオブジェクトを複数のスレッド間で共有し、同時にアクセスすると、すべてのスレッドがシングルトンオブジェクトのコード部分を実行し、独自の実行にラップされます。

また、Thread.currentThread().getId();基本的に実行中のスレッド ID を返す a をシングルトンのメソッドに記述すると、異なるスレッドが独自のメソッド スタックを実行しているため、異なる ID を取得します。ステートレスであることは、それらの間で共有されるシングルトンにフィールドがないことを意味します!

ステートレスとステートフルについて一言

ステートレスとは、Bean に共有する変更可能なフィールドがないことを意味します。つまり、オブジェクトにはメソッドまたは静的なものしかないため、どこでも使用でき、常に同じ結果が返されます。フィールドへのアクセスの同期について心配する必要はありません。

これはstatelessに関する基本的な例です。合計演算のみを実行するクラスがあるとします。

public class StatelessClass{

    public int sum(int a, int b){
        return a+b;
    }

}

同様に、それを抽象クラス (それ自体はインスタンス化できない) として宣言し、そのメソッドをstaticにすることができます。つまり、そのメソッドを呼び出すためにそのインスタンスは必要ありません。

public abstract class StatelessClass{

    /**
    *   I only sum objects
    */
    public static int sum(int a, int b){
        return a+b;
    }

}

次に、それを として使用できます。これは実際にはSingletonStatelessClass.sum(1,1);オブジェクト自体を持つのと非常に似ていますが、Singleton ではアプリケーションで共有される一意のインスタンスがあるという違いがあります。

同様に、注入されてサービスへのアクセスを提供するフィールドを持つことも、オブジェクトの状態を変更するとは見なされません。

public class StatelessServiceClass{

    private Service service;

    public int sum(int a, int b){
        return service.sum(a,b);
    }

    public void setService(Service serv){
        this.service=serv;
    }

}

ただし、変更可能なフィールドを持つと、オブジェクトはステートフルになります。

public class StatefulClass{

    //This fields make the object STATEFUL
    private int totalSum = 0;

    public int sum(int a, int b){
        int sum = a + b;
        totalSum = totalSum + sum;
        if (totalSum > 100)
            System.out.println("This thread "+Thread.currentThread().getId()+
                +" got it!");
        return sum;
    }

}

sum同時に複数のスレッドからアクセスできるため、同期された方法でアクセスされることを保証する必要がありtotalSumます。あなたがそれをしない限り、印刷された文章は真実であるとは限りません。

これはすべて、 @ BalusCによるこの回答のThreadsafety部分でも適切に説明されています。

于 2013-08-31T11:14:07.840 に答える
8

すべてのスレッドには独自のObject oand のコピーがあるため、複数のスレッドが同時にメソッドを呼び出した場合でも、Thread の各メソッド呼び出しには独自のスタックが割り当てられ、ロジックがそこに適用されます。

なぜスレッドセーフなのですか?

スレッド スタックはそれらに対してプライベートであり、他のスレッドが他のスタックに入ることができないため、デフォルトでスレッド セーフです。

注:あなたのこのシングルトンはスレッドセーフであると言えますが、Object o渡されるもの自体がスレッドセーフであるかどうかにも依存するため、アプリケーションがスレッドセーフであるとは言えません。しかし、Singleton の安全性に関する限り、それはスレッドセーフです。

于 2013-08-31T11:17:19.873 に答える
6

「ピザ用語」で考えることができます。あなたはピザカフェに行き、他の数人の男もあなたと一緒に入った. それぞれが注文を出し、自分のテーブルに座った。ピザの箱が到着し、それぞれが自分の食事を食べ始めます。

ここで、カフェはシングルトン、ピザボーイは CPU コア、あなたと他の顧客はスレッド、注文とピザはそれぞれ入力データと出力データ、テーブルはメモリの一部です。

ご覧のとおり、各スレッドには独自のメモリが提供されるため、CPU はデータを区別して混同することがありません。スタックについて尋ねたように、各スレッドには独自のスタックがあるため (メモリ チャンクの一部として)、ここでは重要なプレーヤーではありません。

于 2013-08-31T11:17:02.877 に答える