0

私の教科書の 1 つは、synchronized() の引数はこれでなければならないと述べています... 私はそれが間違っていることを知っています。しかし、synchronized(this) の方が安全なので、常に使用する必要があると聞きました。本当 ?ありがとうございました:)

4

8 に答える 8

5

いいえ、常にこれである必要はありません。また、これがないため、静的メソッドの場合は単純にできません。

また、これに同期するのは間違っていると見なされることもあります。これは、ロック オブジェクトが外部から見えるためです。

public class Example {
    private final Object lock = new Object();

    // does not compile, there is no 'this' in static context.
    public static void staticMethod() {
        synchronized (this) {
        }
    }

    public void method() {
        int x = 3;
        //there is risk that someone else outside our code
        //uses same lock
        synchronized (this) {

        }
        //this lock is private
        synchronized (lock) {
        }
    }
}
于 2012-07-27T14:01:36.330 に答える
1

私の教科書の 1 つは、synchronized() の引数はこれでなければならないと述べています... 私はそれが間違っていることを知っています。

それは正しくありません。教科書が間違っているか、あなたがそれを誤解しています。Java 言語を使用すると、任意の(null 以外の) オブジェクト参照を同期できます。

しかし、synchronized(this) の方が安全なので、常に使用する必要があると聞きました。本当?

いいえ、それも真実ではありません。安全ではありませんし、常にロックオンするべきではありませんthis

実際、「それ自体」をロックする必要がある汎用ライブラリ クラスを作成している場合は、プライベート ロック フィールドを宣言することをお勧めします。例えば

    private final Object myLock = new Object();

...ではなくそのオブジェクトをロックしますthis。これにより、外部コードがなんらかの理由でライブラリ オブジェクトをロックすることを決定し、ライブラリ クラス メソッドと外部コードの間で不要な競合やデッドロックが発生する可能性があるという問題が解消されます。


教科書が言おうとしていたのは、プリミティブ ロックを使用してデータ構造の相互排除と同期を実現するすべてのメソッドは、正しいオブジェクトをロックとして使用する必要があるということだと思います。これは必ずしもデータ構造オブジェクト自体ではありませんが、そのオブジェクトを意味する必要があります... ある意味で。(データ構造を示すオブジェクトをロックしないと、データ構造を使用/更新している間、あるスレッドが他のスレッドを除外しないリスクがあります。)


これは、プライベート ロックが回避しようとしている問題の概要です。

/** This class implements thread-safe getting / setting by synchronizing on 'this' */
public class IntHolder {
    private int value;
    public int getValue() {
        synchronized(this) { return value; }
    }
    public void setValue(int value)
        synchronized(this) { this.value = value; }
}

/* Somewhere else, some other code (the "external code") used a holder instance
   as the lock for some larger-scale synchronization. */
IntHolder h = ...
synchronized (h) {
    /* Do something that takes a long time ... */
}

問題は、外部コードがそのロックを保持している間h、他のスレッドがホルダーの値を読み取ったり変更したりできないことです。それが意図されたものであるなら、それでいいのです。ただし、IntHolder型のスレッドセーフが「単なる実装の詳細」であることを意図している場合、予期しない失敗のケースが発生する可能性があります。

于 2012-07-27T14:04:06.450 に答える
0

ああ、悪名高いJavaで同期(これ)を避けますか?

実際には、違いはありません

public synchronized void doThis() {


}

public void doThis() {
    synchronized (this) {

    }
}

バイトコードレベルを除く。どちらもスレッドセーフに対応しています。(たとえば、同期されたブロック内で同じクラスのロックを設定した場合)デッドロックが発生する可能性があるため、どちらも問題を引き起こします。

デッドロックが心配な場合は、次のlockように専用を使用する必要があります。

public class MyClass {
    private final Object lock = new Object();   //Must be final

    public void doThis() {
        synchronized (lock) {

        }
    }
}

または、Javajava.util.concurrent.Lockインターフェースとjava.util.concurrent.locks.ReentrantLock実装を使用して、基本的にロックを実行します。

于 2012-07-27T14:13:07.467 に答える
0

IMO Synchronized(this) がその特定の場所で良いアイデアかどうかわからない場合は、フィールドとメソッドで「volatile」と「synchronized」を使用することをお勧めします。

簡単に言うと、volatile は組み込みミューテックスを変数に配置します。synchronized は、関数呼び出しに組み込みミューテックスを配置します。同期ブロックは、パラメーターによってロックされたコード部分の周りに組み込みミューテックスを配置します。

通常、オブジェクトをロックしてロックしますが、インスタンス自体をロックしたい場合もあります...ただし、メンバーの1つにのみアクセスする必要がある場合は、クラスインスタンス全体でロックすることに注意してください。 /fields (そもそも Synchronized と volatile を使用して解決できたもの)

これをロックしたい (またはしたくない) 本当の理由は、ロックのスコープです。これをロックすると、ロックが表示されます。プライベート オブジェクトを初期化すると、ロックは隠されます。

于 2012-07-27T14:02:34.390 に答える
0

非静的メソッドを次のように宣言した場合synchronized:

public synchronized void doSomething()
{
    ...
}

で同期されthisます。したがって、上記のような同期された非静的メソッドでsynchronizedブロックを同期することが目標である場合は、 を使用する必要があります。synchronized(this)

しかし、あなたは正しいです:の同期メソッドではなくsynchronized(someOtherObject)の同期メソッドをロックアウトすることを認識している限り、 を書くこともできます。someOtherObjectthis

(ちなみに、静的メソッドの場合、含まれているクラスを表すインスタンスでsynchronized同期します。)Class

于 2012-07-27T14:05:41.400 に答える
0

いいえ、必ずしも を使用する必要はありません。thisのインスタンスではない他のオブジェクトにロックを適用してもthis

 synchronized(obj1){
 -------
 }

 synchronized(obj2){
 -------
 }

単一のメソッドでは、最初にオブジェクトのロックを取得し、obj1次に作業を行って解放し、obj2 のロックを取得する上記のようなものを書くことができます。

于 2012-07-27T14:06:31.683 に答える
0

どのロックを使用してもかまいません。すべての java.lang.Object はロックとして機能できます。同じ変更可能な状態で動作するすべての操作が同じロックを使用していることを確認する必要があります。

とまったくsynchronized(this)同じくらい安全です

private final Object lock = new Object(); synchronized(lock)

于 2012-07-27T14:02:55.693 に答える
0

Synchronized の引数は、単にホールドが置かれるオブジェクトです。引数がどうあるべきかを決定する同期ブロックで何をしたいかによって異なります。を使用thisすると、現在のオブジェクトが保持されます。

個人的な逸話として、私が現在取り組んでいるプロジェクトでは、同期されたすべてのホールドが COM ポート上にあるため、パケットの送信と受信の間に衝突はありません。

于 2012-07-27T14:02:49.970 に答える