web-dev-qa-db-ja.com

「同期」は正確に何をしますか?関数をロックしますか、それともオブジェクト関数をロックしますか?

Javaで「同期」がどのように正確に機能するのか疑問に思っています。

いくつかのフィールドで構成されるボードゲームをモデル化するとします。フィールドをクラス(Field)として実装し、ボードをいくつかのフィールドを含むクラス(Board)として実装します。さらに、プレーヤーがそのフィールドに移動するために、フィールドでメソッドmoveTo(Player pl)をモデル化したとしましょう。各プレイヤーはスレッドで表されます。

すべてのスレッドはいくつかのアクションを同時に実行する必要がありますが(たとえば、ダイスを転がす)、一度に移動するプレーヤーは1人だけである必要があります。

どうすればそれを保証できますか?メソッドmoveTo(Player pl)を同期させるだけで十分ですか?または、一度に1人のプレーヤーだけが移動するようにするには、ボードにカスケードメソッドが必要ですか? (またはより良い解決策はありますか)?

収益を上げるには:
このメソッドを持つすべてのオブジェクトでメソッドを「同期」ロックしますか、それとも現在使用中のオブジェクトでのみメソッドを同期ロックしますか?
そして2番目の場合:このメソッドが実装されているすべてのオブジェクトのメソッドをロックする簡単な方法はありますか?

ありがとうございました!!!

20
speendo

私があなたが望むと思うのは次のとおりです。

class Field {

    // instance of the board
    private Board board; 

    public void moveTo(Player p){ 
        synchronized (board) {
            // move code goes here
        }
    }
}

これにより、ボードごとに一度に1人のプレーヤーだけが移動するようになります。ボード上で同期ロックを取得した場合、一度に1つのフィールドのみが同期ロックに入ることができます。 (1枚のボードを想定)

あなたが単に書いた場合:

public synchronized void moveTo(Player p){ 

プレイヤーが一度に同じフィールドに移動できないことを保証するだけです。これは、メソッドが定義に同期して記述されている場合、オブジェクトレベルでロックされるためです。したがって、フィールドの各インスタンスはそれ自体のロックオブジェクトになります。したがって、プレーヤーは、同じフィールドに移動しない限り、同時に移動することができます。

29
jjnguy

同期は、メソッドではなくオブジェクトをロックします。 Javaには関数がありません。

すべてのオブジェクトでメソッドを1回だけ呼び出す場合は、クラスなどの共有オブジェクトをロックできます。

すべての移動/操作を実行するために必要なスレッドは1つだけであり、これによりコードが大幅に簡素化されることをお勧めします。なぜマルチスレッドにする必要があるのですか?

7
Peter Lawrey

同期により、リソースへのアクセスがロックされます。そのリソースは、関数またはオブジェクト(thisオブジェクトを含む)のいずれかです。

具体的な例がなければ、具体的なアドバイスをすることはできません。

あなたの例では、プレイヤーが一度に1ターンしか取れない場合、なぜ彼らは自分のスレッドにいる必要があるのですか?なぜ彼らは同時にサイコロを振る必要があるのですか?

関数を同期すると、そのインスタンスのバージョンのメソッドへの呼び出しがロックされます(静的メソッドでない場合)。

And if the second is the case: is there an easy way to lock a function for every object that has this function implemented?

これは、設計を再評価できることを示唆しているようです。オブジェクトのインスタンスメソッドは、メソッドを相互に同期させる必要があるように、実際に状態を共有していますか?どうして?

1
Falmarri

使用場所によって異なります。

通常の方法で使用する場合は、問題のオブジェクトの「ロック」オブジェクトのみを取得します。同じオブジェクトの「ロック」オブジェクトへの排他的アクセスが必要な場合、他のスレッドはそのオブジェクトのメソッドを処理できません(同期されていないメソッドはロックへの排他的アクセスを必要としません)。

静的メソッドで使用される場合、クラスを表すオブジェクトのロックオブジェクトを排他的に取得します。同じクラスオブジェクトの「ロック」オブジェクトへの排他的アクセスが必要な場合、他のスレッドはそのクラスオブジェクトのメソッドを処理できません(同期されていないメソッドはロックへの排他的アクセスを必要としません)。

明示的に指定されたオブジェクトとともに使用すると、明示的に指定されたオブジェクトのロックオブジェクトのみを取得します。この場合も、その間、他のスレッドがそのオブジェクトのロックを排他的に取得することはできません。

同期されたブロックのスコープを離れると、ロックの排他的保持を放棄します。

1
Edwin Buck