web-dev-qa-db-ja.com

Javaで同期静的メソッドはどのように機能しますか?

Hibernate関数を呼び出して基本的なデータアクセスを実現する静的メソッドを持つutilクラスがある場合。メソッドsynchronizedを作成することがスレッドセーフを確保するための正しいアプローチであるかどうか疑問に思っています。

これにより、同じDBインスタンスへの情報のアクセスを防ぐことができます。ただし、特定のクラスから呼び出されたときに、すべてのクラスに対してgetObjectByIdが呼び出されるのを次のコードが防止しているのかどうかは確信しています。

public class Utils {
     public static synchronized Object getObjectById (Class objclass, Long id) {
           // call hibernate class
         Session session = new Configuration().configure().buildSessionFactory().openSession();
         Object obj = session.load(objclass, id);
         session.close();
         return obj;
     }

     // other static methods
}
170
tomato

静的メソッドロックで同期を使用すると、 クラスメソッドと属性を同期 (インスタンスメソッドと属性とは対照的に)

したがって、あなたの仮定は正しいです。

メソッドを同期させることがスレッドセーフを保証するための正しいアプローチであるかどうか疑問に思っています

あんまり。代わりに、RDBMSでその作業を行う必要があります。彼らはこの種のものが得意です。

データベースへのアクセスを同期することによって得られる唯一のものは、アプリケーションを非常に遅くすることです。さらに、投稿したコードでは、毎回セッションファクトリを構築しているため、アプリケーションは実際のジョブを実行するよりもDBにアクセスするのにより多くの時間を費やします。

次のシナリオを想像してください。

クライアントAとBは、テーブルTのレコードXに異なる情報を挿入しようとします。

RDBMSは、Aから半分の情報を、Bから半分の情報を同時に挿入できないため、DBでとにかくこれが発生する場合、アプローチで唯一得られるのは、次から次へと呼び出されるようにすることです。 。結果は同じになりますが、5倍(またはそれ以上)遅くなります。

おそらく、Hibernateドキュメントの "Transactions and Concurrency" の章をご覧になるとよいでしょう。ほとんどの場合、あなたが解決しようとしている問題はすでに解決されており、より良い方法です。

134
OscarRyz

より一般的に質問に対処するには...

メソッドの同期を使用することは、実際には単なる略記であることに注意してください(クラスがSomeClassであると仮定します):

synchronized static void foo() {
    ...
}

と同じです

static void foo() {
    synchronized(SomeClass.class) {
        ...
    }
}

そして

synchronized void foo() {
    ...
}

と同じです

void foo() {
    synchronized(this) {
        ...
    }
}

任意のオブジェクトをロックとして使用できます。静的メソッドのサブセットをロックする場合、次のことができます。

class SomeClass {
    private static final Object LOCK_1 = new Object() {};
    private static final Object LOCK_2 = new Object() {};
    static void foo() {
        synchronized(LOCK_1) {...}
    }
    static void fee() {
        synchronized(LOCK_1) {...}
    }
    static void fie() {
        synchronized(LOCK_2) {...}
    }
    static void fo() {
        synchronized(LOCK_2) {...}
    }
}

(非静的メソッドの場合、ロックを非静的フィールドにしたいでしょう)

221

静的メソッドは、クラスをロックのオブジェクトとして使用します。この例では、Utils.classです。はい、大丈夫です。

17
starblue

static synchronizedは、クラスのClassオブジェクトのロックを保持することを意味します。synchronizedは、そのクラスのオブジェクト自体のロックを保持することを意味します。つまり、(実行中の)スレッド内の非静的同期メソッドにアクセスしている場合でも、別のスレッドを使用して静的同期メソッドにアクセスできます。

そのため、ある時点で複数のスレッドが同じ種類の2つのメソッド(2つの静的メソッドまたは2つの非静的メソッド)にアクセスすることはできません。

14
prasad

一度に1つのスレッドのみがDBにアクセスできるようにしたいのはなぜですか?

データベースドライバーの仕事です必要なロックを実装するために、Connectionが一度に1つのスレッドでのみ使用されると仮定します!

ほとんどの場合、データベースは複数の並列アクセスを完全に処理できます。

9
oxbow_lakes

データベース内のデータと関係がある場合は、データベース分離ロックを利用して達成してみませんか?

2
Ray Lu

あなたの質問に答えるには、はい、そうです:synchronizedメソッドは一度に複数のスレッドで実行できません。

2
David Z