スレッドT1がクラスレベルのロックを取得してメソッドm1に入る場合、これは別のスレッドT2がオブジェクトレベルのロックを取得して別のメソッドm2を実行できないことを意味しますか?
いいえ、そうではありません。 「クラスレベルのロック」は、別のオブジェクト、つまりSomeClass.class
に対する通常のロックです。 「オブジェクトレベルロック」はthis
をロックします。
編集:用語の理解に従っていることを確認するために、m1とm2を同時に定義できるかどうかを以下で定義しています。
public class SomeClass {
public synchronized static void m1() {
//do something
}
public synchronized void m2() {
//do something
}
}
そして答えは「はい」です。m1とm2は同時に実行できます。機能的にはこれと同等です:
public class SomeClass {
public static void m1() {
synchronized (SomeClass.class) {
//do something
}
}
public void m2() {
synchronized (this) {
//do something
}
}
}
完全に異なるオブジェクトで同期しているため、相互に排他的ではありません。
オブジェクトレベルのロックは、非静的メソッドまたは非静的コードブロックを同期して、クラスの特定のインスタンスでコードブロックを実行できるスレッドが1つだけになるようにする場合のメカニズムです。これは、インスタンスレベルのデータスレッドを安全にするために常に行う必要があります。これは以下のように行うことができます:
public class DemoClass
{
public synchronized void demoMethod(){}
}
or
public class DemoClass
{
public void demoMethod(){
synchronized (this)
{
//other thread safe code
}
}
}
or
public class DemoClass
{
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
クラスレベルのロックにより、実行時に使用可能なすべてのインスタンスのいずれかで、複数のスレッドが同期ブロックに入ることを防止します。つまり、実行時にDemoClassのインスタンスが100個ある場合、インスタンスのいずれか1つでdemoMethod()を実行できるスレッドは一度に1つだけで、他のすべてのインスタンスは他のスレッドに対してロックされます。これは、静的データスレッドを安全にするために常に行う必要があります。
public class DemoClass
{
public synchronized static void demoMethod(){}
}
or
public class DemoClass
{
public void demoMethod(){
synchronized (DemoClass.class)
{
//other thread safe code
}
}
}
or
public class DemoClass
{
private final static Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
}
Javaには、2種類のロックがあります:
Staticメソッドの場合、ロックは常にクラスでチェックされますが、インスタンスメソッドの場合、ロックは常にオブジェクトでチェックされます。
例:
show1()
はnon staticであり、show()
はstatic。現在、show()
はクラス名(またはオブジェクト)によって呼び出され、show1()
はオブジェクトによって呼び出されるため、両方のメソッドが2つのスレッドから同時にアクセスできます。
class Shared{
static int x;
static synchronized void show(String s,int a){
x=a;
System.out.println("Starting in method "+s+" "+x);
try{
Thread.sleep(2000);
}
catch(Exception e){ }
System.out.println("Ending from method "+s+" "+x);
}
synchronized void show1(String s,int a){
x=a;
System.out.println("Starting show1 "+s);
try{
Thread.sleep(2000);
}
catch(Exception e){ }
System.out.println("Ending from show1 "+s);
}
}
class CustomThread extends Thread{
Shared s;
public CustomThread(Shared s,String str){
super(str);
this.s=s;
start();
}
public void run(){
Shared.show(Thread.currentThread().getName(),10);
}
}
class CustomThread1 extends Thread{
Shared s;
public CustomThread1(Shared s,String str){
super(str);
this.s=s;
start();
}
public void run(){
s.show1(Thread.currentThread().getName(),20);
}
}
public class RunSync {
public static void main(String[] args) {
Shared sh=new Shared();
CustomThread t1=new CustomThread(sh,"one");
CustomThread1 t2=new CustomThread1(sh,"two");
}
}
出力:
Starting in method one 10
Starting show1 two
Ending from method one 20
Ending from show1 two
スレッドT1がクラスレベルのロックを取得してメソッドm1に入る場合、これは別のスレッドT2がオブジェクトレベルのロックを取得して別のメソッドm2を実行できないことを意味しますか?
オブジェクトレベルのロックとクラスレベルのロックは異なります。上記の場合、T2はオブジェクトレベルのロックを取得することでメソッドm2を実行できます。しかし、m2がstatic synchronized
、T1がメソッドm1のクラスレベルのロックを解放しない限り、T2はm2メソッドを呼び出すことができません。
同じオブジェクトでsynchronized
メソッドを2回呼び出すことはできません。 1つのスレッドがオブジェクトのsynchronized
メソッドを実行している場合、最初のスレッドがオブジェクトで完了するまで、同じオブジェクトのsynchronized
メソッドを呼び出す他のすべてのスレッドがブロックします(実行を中断します)。
オブジェクトOに2つのsynchronized
メソッドm1とm2があるとします。スレッドT1がメソッドm1の実行中の場合、スレッドT2は、スレッドT1がロックを解放しない限り、同じオブジェクトOでメソッドm2を呼び出すまで待機する必要があります。メソッドm1。
スレッドは、クラスに関連付けられたClass
オブジェクトの組み込みロックを取得します。したがって、クラスのstatic
フィールドへのアクセスは、クラスのインスタンスのロックとは異なるロックによって制御されます。
メソッドm1がstatic synchrnozed
およびメソッドm2もstatic synchronized
と2つの異なるオブジェクトo1とo2があります。
スレッドT1がオブジェクトo1でメソッドm1の実行中である場合、スレッドT1がメソッドm1のロックを解放しない限り、スレッドT2はオブジェクトo2でメソッドm2を呼び出すまで待機する必要があります。
Javaのオブジェクトおよびクラスレベルのロックを理解する例
1)オブジェクトレベルロックの例
package com.test;
public class Foo implements Runnable {
@Override
public void run() {
Lock();
}
public void Lock() {
System.out.println(Thread.currentThread().getName());
synchronized(this) {
System.out.println("in block " + Thread.currentThread().getName());
System.out.println("in block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Foo b1 = new Foo();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Foo b2 = new Foo();
Thread t3 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
出力:
t1
t3
t2
in block t3
in block t1
in block t3 end
in block t1 end
in block t2
スレッドt1およびt2がブロックしても、t3はブロックしないことに注意してください。ロックはこのオブジェクトとスレッドに配置されているためt3はこのオブジェクトとは異なりますスレッドt1、t2よりも
2)クラスレベルロックの例
オブジェクトレベルロックのコード。Foo.classのみが同期ブロックに追加されます。 Fooクラスのオブジェクトを使用して作成されているすべてのスレッドはブロックされます。
package com.test;
public class Foo implements Runnable {
@Override
public void run() {
Lock();
}
public void Lock() {
System.out.println(Thread.currentThread().getName());
synchronized(Foo.class) {
System.out.println("in block " + Thread.currentThread().getName());
System.out.println("in block " + Thread.currentThread().getName() + " end");
}
}
public static void main(String[] args) {
Foo b1 = new Foo();
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b1);
Foo b2 = new Foo();
Thread t3 = new Thread(b2);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
出力:
t1
t3
in block t1
in block t1 end
t2
in block t3
in block t3 end
in block t2
in block t2 end
同期ブロックは、同じスレッドに対して実行されます。
クラスレベルのロックは、キーワード「Static Synchronized」によって達成されます。オブジェクトレベルは、synchronizedキーワードによってのみ達成されます。オブジェクトレベルのロックは、同じオブジェクトが異なるスレッドを介して動作するのを制限するために達成されます。クラスレベルのロックは、オブジェクトの動作を制限するために達成されます。 。
クラスレベルのロックのさまざまな方法:1)パブリッククラスDemoClass {
public static synchronized void demoMethod(){
//dosomething
}
}
2)
パブリッククラスDemoClass {
public void demoMethod(){
synchronized(DemoClass.class){
//dosomething
}
}
}
3)
パブリッククラスDemoClass {
private final static Object lock = new Object();
public void demoMethod(){
synchronized(lock){
//dosomething
}
}
}
いいえ、どちらも同時に実行できます。 1.クラスレベルのロックが1つのメソッドに適用された場合synchronized(SomeClass.class)であり、他のメソッドにオブジェクトレベルのロックが適用された場合synchronized(this)の場合、両方を実行できます同時。
両方のメソッドにクラスレベルのロックが適用されている場合のみ、同時実行は行われません。
理由:クラスの場合、jvmはJava.lang.Classのオブジェクトを作成します。つまり、Javaのすべてがオブジェクトです。したがって、クラスレベルのロックが2つのメソッドに適用されると、共通のロックが適用されますクラスオブジェクトとすべてのオブジェクトに単一のロックがあるため、すべてのスレッドは待機しますが、2番目のメソッドを呼び出すために異なるインスタンスが使用され、そのときにインスタンスレベルのロックが適用されると、クラスオブジェクトのロックとは異なるこのオブジェクトロックが適用されます。同時実行が可能です。
インスタンスレベルのロック、インスタンスレベルのロックを使用して一度に実行できるのは単一のスレッドのみです。
public class Refactor implements Runnable {
private Object obj;
public Refactor(Object obj)
{
this.obj = obj;
}
public void run() {
if (Thread.currentThread().getName().equalsIgnoreCase("Test1")) {
test1();
} else {
test2();
}
}
public void test1() {
synchronized (obj) {
System.out.println("Test1");
}
}
public synchronized void test2() {
synchronized (obj) {
System.out.println("Test2");
}
}
public static void main(String[] args) {
Object obj = new Object();
Thread t1 = new Thread(new Refactor(obj));
t1.setName("Test1");
t1.start();
Thread t2 = new Thread(new Refactor(obj));
t2.setName("Test2");
t2.start();
}
}
クラスレベルのロック、クラスレベルのロックを使用すると、一度に実行できるスレッドは1つだけです。
public class Refactor implements Runnable {
private Object obj;
public Refactor(Object obj)
{
this.obj = obj;
}
public void run() {
if (Thread.currentThread().getName().equalsIgnoreCase("Test1")) {
test1();
} else {
test2();
}
}
public static void test1() {
synchronized (Refactor.class) {
System.out.println("Test1");
}
}
public static synchronized void test2() {
synchronized (Refactor.class) {
System.out.println("Test2");
}
}
public static void main(String[] args) {
Object obj = new Object();
Thread t1 = new Thread(new Refactor(obj));
t1.setName("Test1");
t1.start();
Thread t2 = new Thread(new Refactor(obj));
t2.setName("Test2");
t2.start();
}
}
静的同期メソッドと非静的同期メソッドの両方が異なるオブジェクトにロックされているため、同時にまたは同時に実行できる可能性があります。
クラスレベルのロックとインスタンスレベルのロックはどちらも異なります。どちらもお互いのロック状態を妨害しません。クラスの1つのインスタンスがすでにスレッドによってロックされている場合、ロックが最初のスレッドによって解放されない限り、別のスレッドはそのインスタンスのロックを取得できません。同じ動作がクラスレベルのロックにもあります。
ただし、スレッドがクラスレベルのロックを取得すると、別のスレッドがそのインスタンスの1つでロックを取得できます。どちらも並行して動作します。`
package lock;
class LockA implements Runnable {
@Override
public void run() {
synchronized (LockA.class) {
System.out.println("Class");
try {
Thread.sleep(60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestClassVsInstanceLock {
public static void main(String[] args) {
final LockA a = new LockA();
final LockA b = new LockA();
try {
Thread t = new Thread(a);
Thread t1 = new Thread() {
@Override
public void run() {
synchronized (b) {
System.out.println("Instance 1"+ currentThread().currentThread().holdsLock(b));
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
t1.start();
synchronized (a) {
System.out.println("Instance2");
Thread.sleep(10 * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
`
これは次を出力します:-Instance2 Class Instance 1true
すべてが一時停止することなく即座に印刷されます。