8

私には、すべての静的メソッドはJavaWebアプリケーションのコンテキスト内にあるべきだと言った友人がいsynchronizedます。本当?私はこれに関して他の多くのスタックオーバーフローページを読みました。私が信じるようになったのは、次の場合にのみ同期する必要があるということです。

  1. 複数のスレッド(スレッドプールを備えたSevletコンテナの場合と同様)
  2. シングルClassLoader
  3. セッションデータであろうと静的メンバーデータであろうと、スレッド間で共有されるデータ。
  4. 共有データは変更可能である必要があります。読み取り専用データは共有しても問題ありません。

これに基づいて、静的メンバーは同期する必要があると思いますが、静的メソッドは同期しないでください。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadTest {

    static String staticString = "";

    // This static method is safe b/c it only uses local data.
    // It does not use any shared mutable data.
    // It even uses a string builder.
    static String safeStaticMethod(String in) {
        // This also proves that StringBuilder is safe
        // When used locally by a thread.
        StringBuilder sb = new StringBuilder();
        sb.append("Hello: ");
        sb.append(in);
        return sb.toString();
    }

    // This static method is not safe b/c it updates and reads
    // shared mutable data among threads.
    // Adding synchronized will make this safe.
    static String unsafeStaticMethod(String in) {
        staticString = in;
        StringBuffer sb = new StringBuffer();
        sb.append("Hello: ");
        sb.append(staticString);
        return sb.toString();
    }

    public static void main(String[] args) {
        ThreadTest test = new ThreadTest();
        test.staticMethodWithLocalData();
        test.staticMethodWithStaticData();
    }

    public void staticMethodWithLocalData() {

        ExecutorService executor = Executors.newFixedThreadPool(2);
        final int iterations = 100000;

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!safeStaticMethod("Thread1").equals("Hello: Thread1")) {
                        System.out.println("safeStaticMethod at " + index);
                    }
                }
            }
        });

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!safeStaticMethod("Thread2").equals("Hello: Thread2")) {
                        System.out.println("safeStaticMethod at " + index);
                    }
                }
            }
        });
    }

    public void staticMethodWithStaticData() {

        ExecutorService executor = Executors.newFixedThreadPool(2);
        final int iterations = 100000;

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!unsafeStaticMethod("Thread1").equals("Hello: Thread1")) {
                        System.out.println("unsafeStaticMethod at " + index);
                    }
                }
            }
        });

        executor.submit(new Runnable() {

            @Override
            public void run() {
                for (int index = 0; index < iterations; ++index) {
                    if (!unsafeStaticMethod("Thread2").equals("Hello: Thread2")) {
                        System.out.println("unsafeStaticMethod at " + index);
                    }
                }
            }
        });
    }
}

このコードはポイントを証明していますか?

編集:これは、要点を証明するために私がハックした使い捨てコードのほんの一部です。

4

5 に答える 5

12

いいえ、すべての静的メソッドを同期する必要はありません。私が見る限り、あなたのリストは基本的に完全です。静的メソッドの場合は特に注意してください

  1. 変更可能な静的メンバーにアクセスする、または
  2. 変更可能なオブジェクトへの参照が渡されます。

スレッドがないと意味がないので、1(そもそもスレッドがある)が前提条件であることは言うまでもsynchronizeありません。

私は2を聞いたことがないので、それが考慮事項であるかどうかはわかりません。

于 2013-02-13T20:32:00.943 に答える
4

いいえ、それは真実ではなく、有害であると確信しています。すべてのアプリケーションが並行している必要はありません。また、並行している必要があるアプリケーションでも、すべてのコードが並行している必要はありません。

より多くの証拠として、Stringのソースを見てください。 そこには多くの静的メソッドがありますが、同期されたメソッドは1つしか見つかりませんでした。また、そのメソッドは静的でもありません。

于 2013-02-13T20:34:21.617 に答える
2

静的メソッドは、Webアプリケーションで同期されることはほとんどありません。アプリケーションを使用するのは3人の経理チームだけであると100%確信している場合を除いて、会社全体で離陸し、突然すべてが停止した場合は、顔を赤くすることをいとわないでしょう。

グローバルなブロッキング共有リソースの作成は、スケーラビリティの完全な失敗です。また、アプリケーションサーバーをクラスター化する必要が生じた場合、多くの頭痛の種を引き起こし、Terracottaスタイルのソリューションに縛られる可能性があります。

于 2013-02-13T20:53:58.540 に答える
1

Webアプリケーション(サーブレット/ JSPを使用したビルドなど)では、マルチスレッドアクセシビリティの哲学全体に挑戦するため、メソッドを同期化することは常に避けてください。その場で、常に、同期されたブロック内に、1つずつアクセスする必要がある唯一の必要なコードを配置するようにしてください。

于 2014-05-14T00:56:56.840 に答える
1

全くない。ほとんどの場合、私が遭遇した静的メソッドは静的変数を変更しないため、同期する必要はありません。

簡単に理解するために、

    //sample static util method to get string in upper case    
    public static String getName(String name){
        return a.toUpperCase();
    }

上記のメソッドは数千のスレッドで呼び出すことができますが、このメソッドは引数-文字列名のみを必要とし、それはスレッドスタックからのものであるため、スレッドセーフになります。スレッド間で共有されるデータではありません。

考えてみてください。すべての静的メソッドが同期されている場合、Webアプリケーションは非常に遅く、使用するのが無気力になります。単一のスレッドがメソッドにアクセスしようとするたびに、クラスレベルのロックが必要になります。

JDKが提供するAPIには多くの静的メソッドがあります。これらすべてが同期されていれば、JAVAを使用しないことは間違いありません。

あなたの場合、静的メソッドによって変更されている静的変数(クラスレベル変数)があります。はい、複数のスレッドが作成され、それらが静的メソッドにアクセスしようとしている場合、スレッド干渉の可能性があります。それらの間には共有データがあるため、スレッドセーフではありません。

ほとんどの場合、静的メソッドは、渡される引数に応じた効用関数です。

同期されていない静的メソッドは、静的クラス変数を変更しない場合、スレッドセーフであることに注意してください。

于 2017-02-01T09:57:37.043 に答える