83

アプリケーションのさまざまなユーティリティクラスで特に使用される静的メソッドのスレッドセーフを確保できる一般的な方法またはルールの出口はありますか? ここで特に指摘したいのは、Web アプリケーションのスレッド セーフです。

不変オブジェクトをパラメーターとして使用する静的メソッドはスレッドセーフであり、可変オブジェクトはそうではないことはよく知られています。

を操作するためのユーティリティ メソッドがありjava.util.Date、そのメソッドが のインスタンスを受け入れる場合java.util.Date、このメソッドはスレッド セーフではありません。次に、パラメーターの受け渡し方法を変更せずにスレッドセーフにする方法は?

public class DateUtils {

    public static Date getNormalizeDate(Date date) {
        // some operations
    }   
}

また、クラスはjavax.faces.context.FacesContext可変ですか?このクラスのインスタンスをそのような静的ユーティリティ メソッドに渡すことはスレッド セーフですか?

インスタンスをパラメーターとして渡すことができる、または渡すことができないクラスのこのリストは、長くなる可能性があります。では、このようなユーティリティ クラスのコードを記述する際に留意すべき点は何でしょうか。

4

7 に答える 7

94

パラメータとして不変オブジェクトを使用する静的メソッドはスレッドセーフであり、可変オブジェクトはそうではないことはよく知られています。

私はこれに異議を唱えます。メソッドに渡される引数は、スレッドごとのイディオムであるスタックに格納されます。

パラメータがaなどの可変オブジェクトである場合は、Date他のスレッドが他の場所で同時にパラメータを変更していないことを確認する必要があります。しかし、それはメソッドのスレッドセーフとは関係のない別の問題です。

投稿したメソッドはスレッドセーフです。状態を維持せず、引数のみを操作します。

Java Concurrency in Practice、またはJavaのスレッドセーフに関する同様の本を読むことを強くお勧めします。これは複雑なテーマであり、StackOverflowのいくつかの回答では適切に対処できません。

于 2012-12-17T09:09:52.697 に答える
26

クラスはメンバー変数を保持しないため、メソッドはステートレス (ローカル変数と引数のみを使用) であり、スレッド セーフです。

それを呼び出すコードはスレッドセーフではないかもしれませんが、それは別の議論です。たとえば、Date はスレッド セーフではありません。呼び出しコードが別のスレッドによって書き込まれた Date を読み取る場合、Date の書き込みおよび読み取りコードで適切な同期を使用する必要があります。

于 2012-12-17T09:07:16.820 に答える
14

JVM の構造上、ローカル変数、メソッド パラメータ、および戻り値は本質的に「スレッド セーフ」です。ただし、インスタンス変数とクラス変数は、クラスを適切に設計した場合にのみスレッドセーフになります。詳細はこちら

于 2016-10-05T16:23:55.033 に答える
7

メソッドが開始されたらすぐにその(変更可能な)オブジェクトのコピーを作成し、元のパラメーターの代わりにコピーを使用することをお勧めします。

このようなもの

public static Date getNormalizeDate(Date date) {
    Date input = new Date(date.getTime());
    // ...
}
于 2012-12-17T09:04:17.087 に答える
7

これについては、次のように考えています。CampSite (静的メソッド) を想像してみてください。キャンピングカーとして、リュックサックにたくさんのオブジェクトを持ち込むことができます (これは、スタックで渡される引数です)。CampSite は、テントやキャンプ ストーブなどを置く場所を提供してくれますが、CampSite が自分のオブジェクトを変更することだけを許可している場合、それはスレッドセーフです。CampSite は何もないところから何かを作成することもでき ( FirePit firepit = new FirePit();)、これもスタック上に作成されます。

ラックスタックにすべてのオブジェクトを入れていつでも姿を消すことができ、他のキャンパーの 1 人が現れて、前回姿を消したときとまったく同じことを行うことができます。この CampSite の別のスレッドは、他のスレッドで作成された CampSite スタック上のオブジェクトにアクセスできません。

campStove が 1 つだけあるとします (CampStove の単一のオブジェクトであり、個別のインスタンス化ではありません)。少し想像力を働かせて CampStove オブジェクトを共有している場合、マルチスレッドに関する考慮事項があります。キャンプストーブの電源を入れて、消えて、他のキャンピングカーがオフにした後に再び現れることはしたくありません。CampStove クラス、CampSite を呼び出していたメソッド、または CampSite 自体のどこかに同期を配置する必要がありますが、Duncan Jonesが言うように、「それは別の問題です」。

static CampSite オブジェクトの個別のインスタンス化でキャンプを行っていたとしても、campStove を共有すると、同じマルチスレッドの考慮事項があることに注意してください。

于 2018-01-21T16:09:16.127 に答える