回答:
どちらの方法でも同じモニターがロックされます。したがって、異なるオブジェクトから同じオブジェクトに対して同時に実行することはできません(2つのメソッドのいずれかが終了するまでブロックされます)。
obj.methodB()
と同義であるA.methodB()
ときmethodB()
ですstatic
。したがって、はい、それらは(オブジェクトではなく、クラスのモニターで)ブロックします。
.class
オブジェクトのロックを使用することに注意してください。だからあなたが持っている場合class A {static synchronized void m() {} }
。次に、1つのスレッドがnew A().m()
それを呼び出してnew A()
オブジェクトのロックを取得します。次に、別のスレッドがA.m()
それを呼び出すと、スレッドがこの種のロックを所有していないときにオブジェクトのロックが検索されるため、問題は発生しません。ですから、メソッド宣言にもかかわらず、それがactualy アクセスされた 2つの異なるスレッドで同時にし。したがって、オブジェクト参照を使用して静的メソッドを呼び出さないでくださいA.class
synchronized
この例では、methodAとmethodBはインスタンスメソッドです(静的メソッドとは対照的)。パッティングsynchronized
スレッドは、スレッドがそのメソッド内の任意のコードの実行を開始する前に、メソッドがコールされているオブジェクトのインスタンスのロック(「固有ロック」)を取得しなければならないことをインスタンスメソッド手段に。
同期とマークされた2つの異なるインスタンスメソッドがあり、異なるスレッドが同じオブジェクトでそれらのメソッドを同時に呼び出している場合、それらのスレッドは同じロックをめぐって競合します。1つのスレッドがロックを取得すると、他のすべてのスレッドは、そのオブジェクトのすべての同期されたインスタンスメソッドから遮断されます。
2つのメソッドを同時に実行するには、次のように異なるロックを使用する必要があります。
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
同期ブロック構文では、ブロックに入るには、実行中のスレッドが固有のロックを取得する必要がある特定のオブジェクトを指定できます。
理解しておくべき重要なことは、個々のメソッドに「同期」キーワードを設定している場合でも、コアコンセプトは舞台裏の本質的なロックであるということです。
Javaチュートリアルが関係を説明する方法は次のとおりです。
同期は、組み込みロックまたはモニターロックと呼ばれる内部エンティティを中心に構築されます。(API仕様では、多くの場合、このエンティティを単に「モニター」と呼びます。)組み込みロックは、同期の両方の側面で役割を果たします。オブジェクトの状態への排他的アクセスを強制し、可視性に不可欠な発生前の関係を確立します。
すべてのオブジェクトには、固有のロックが関連付けられています。慣例により、オブジェクトのフィールドへの排他的で一貫したアクセスを必要とするスレッドは、オブジェクトにアクセスする前にオブジェクトの固有のロックを取得し、それらが完了したら固有のロックを解放する必要があります。スレッドは、ロックを取得してからロックを解放するまでの間に、固有のロックを所有していると言います。スレッドが固有のロックを所有している限り、他のスレッドは同じロックを取得できません。他のスレッドは、ロックを取得しようとするとブロックされます。
ロックの目的は、共有データを保護することです。上記のサンプルコードに示すように、各ロックが異なるデータメンバーを保護する場合にのみ、個別のロックを使用します。
static synchronized
または、次のようなものを使用しますsynchronized (A.class)
Javaスレッドは、インスタンス同期Javaメソッドに入るとオブジェクトレベルのロックを取得し、静的同期Javaメソッドに入るとクラスレベルのロックを取得します。
あなたの場合、メソッド(インスタンス)は同じクラスです。したがって、スレッドがJava同期メソッドまたはブロックに入ると、ロック(メソッドが呼び出されるオブジェクト)を取得します。したがって、最初のメソッドが完了し、lock(on object)が解放されるまで、同じオブジェクトで他のメソッドを同時に呼び出すことはできません。
private final Object lock = new object();
同期で使用して、1つのスレッドのみがどちらのメソッドも実行できるようにすることができますか?ありがとう
あなたのケースでは、クラスの同じインスタンスで2つのメソッドを同期しました。したがって、これら2つのメソッドは、クラスAの同じインスタンスの異なるスレッドで同時に実行することはできません。ただし、異なるクラスAインスタンスで実行することはできます。
class A {
public synchronized void methodA() {
//method A
}
}
と同じです:
class A {
public void methodA() {
synchronized(this){
// code of method A
}
}
}
private final Object lock = new Object();
使用lock
すると、ステートメントはtrueになりますか?IMOはObjectがすべてのオブジェクトの親クラスであるため、スレッドがクラスの異なるインスタンスにある場合でも、同期ブロック内のコードに一度にアクセスできるのは1つだけです。ありがとう。
オラクルのドキュメントリンクから
メソッドを同期させると、2つの効果があります。
まず、同じオブジェクト上で同期メソッドの2つの呼び出しをインターリーブすることはできません。1つのスレッドがオブジェクトの同期メソッドを実行しているとき、同じオブジェクトの同期メソッドを呼び出す他のすべてのスレッドは、最初のスレッドがオブジェクトで完了するまでブロックします(実行を中断します)。
第2に、同期メソッドが終了すると、同じオブジェクトの同期メソッドの以降の呼び出しと、前に発生する関係が自動的に確立されます。これにより、オブジェクトの状態の変更がすべてのスレッドに表示されることが保証されます
これはあなたの質問に答えます:同じオブジェクトで、最初の同期されたメソッドの実行が進行中の場合、2番目の同期されたメソッドを呼び出すことはできません。
あなたのコードを以下のものと考えてください:
class A {
public void methodA() {
synchronized(this){
//method A body
}
}
public void methodB() {
synchronized(this){
// method B body
}
}
したがって、メソッドレベルでの同期は、単に同期(これ)を意味します。スレッドがこのクラスのメソッドを実行する場合、実行を開始する前にロックを取得し、メソッドの実行が終了するまでロックを保持します。
しかし、methodA()がまだ実行されている間に、別のスレッドでmethodB()を実行できますか?(同じオブジェクト)
確かに、それは不可能です!
したがって、複数のスレッドが同じオブジェクトで同時に同期されたメソッドをいくつでも実行することはできません。
明確に言うと、オブジェクトレベルのロックと他のクラスレベルのロックがあるため、静的同期メソッドと非静的同期メソッドの両方を同時にまたは同時に実行できる可能性があります。
同期が簡単ではない同期の重要なアイデアは、同じオブジェクトインスタンスでメソッドが呼び出された場合にのみ効果があるということです。回答とコメントですでに強調表示されています-
以下のサンプルプログラムは、同じことを明確に示すことです-
public class Test {
public synchronized void methodA(String currentObjectName) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}
public synchronized void methodB(String currentObjectName) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}
public static void main(String[] args){
Test object1 = new Test();
Test object2 = new Test();
//passing object instances to the runnable to make calls later
TestRunner runner = new TestRunner(object1,object2);
// you need to start atleast two threads to properly see the behaviour
Thread thread1 = new Thread(runner);
thread1.start();
Thread thread2 = new Thread(runner);
thread2.start();
}
}
class TestRunner implements Runnable {
Test object1;
Test object2;
public TestRunner(Test h1,Test h2) {
this.object1 = h1;
this.object2 = h2;
}
@Override
public void run() {
synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
//noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}
// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
try {
object1.methodA("object1");
object1.methodB("object1");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
try {
object1.methodA("object1");
object2.methodB("object2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
異なるオブジェクトインスタンスでメソッドが呼び出された場合、期待どおりに同時アクセスが許可される方法の出力の違いに注意してください。
出力リレーnoEffectOfSynchronizedAsMethodsCalledOnDifferentObjects() コメント -the出力はmethodBアウト>でmethodAアウト.. methodB>に順番methodAであります
とを有する出力リレーsynchronizedEffectiveAsMethodsCalledOnSameObject()は コメント -強調表示されたセクション内のスレッド1とThread0によってmethodAの出力が示す同時アクセスを-
スレッドの数を増やすと、スレッドがさらに目立ちます。
いいえ、不可能です。可能であれば、両方のメソッドが同じ変数を同時に更新して、データを簡単に破損する可能性があります。
単一のオブジェクトで共通の同期メソッドを実行する2つの異なるスレッド。オブジェクトは同じであるため、1つのスレッドが同期メソッドでそれを使用すると、ロックを検証する必要があり、ロックが有効になっている場合、このスレッドは待機状態になります。ロックが無効になっている場合、オブジェクトにアクセスできますが、アクセスするとロックが有効になり、実行が完了したときにのみロックが解除されます。別のスレッドが到着すると、ロックを検証します。有効になっているため、最初のスレッドが実行を完了するまで待機し、オブジェクトに設定されたロックを解放します。ロックが解放されると、2番目のスレッドがオブジェクトにアクセスし、実行されるまでロックを有効にします。したがって、実行は同時ではなく、両方のスレッドが1つずつ実行されます。