[英]Synchronization between two threads using same and different instance of class?
I would like to clear few doubts and extending question from here - synchronization in two methods in the same class .我想从这里清除一些疑问并扩展问题 - 同一类中两种方法的同步。
public class Demo {
public synchronized void methodA(){
System.out.println("Method A");
}
public synchronized void methodB(){
System.out.println("Method B");
}
public static void main(String[] args) {
Demo demo = new Demo();
Demo demo1 = new Demo();
Thread thread1 = new Thread(() -> demo.methodA());
thread1.start();
Thread thread2 = new Thread(() -> demo1.methodB());
thread2.start();
}
}
locks work at the instance level, not at the class level.锁在实例级别工作,而不是在类级别。
Case-1: For each instance of Demo
at most one between method1 and method2 can be running at any given moment.案例 1:对于每个
Demo
实例,method1 和 method2 之间最多有一个可以在任何给定时刻运行。 This is clear.这是清楚的。
Case-2: Two different instances are calling two separate method, will still the thread block each other?案例 2:两个不同的实例正在调用两个单独的方法,线程仍然会互相阻塞吗?
Using Static Synchronized the same method -使用静态同步相同的方法 -
public class Demo {
public static synchronized void methodA(){
System.out.println("Method A");
}
public static synchronized void methodB(){
System.out.println("Method B");
}
public static void main(String[] args) {
Demo demo = new Demo();
Demo demo1 = new Demo();
Thread thread1 = new Thread(() -> demo.methodA());
thread1.start();
Thread thread2 = new Thread(() -> demo1.methodB());
thread2.start();
}
}
Case-3: Say same instance of demo class demo
is used to call two separate method, will they block each other?案例3:假设demo类
demo
同一个实例被用来调用两个单独的方法,它们会互相阻塞吗?
Case-4: Say different instances of Demo class demo
and demo1
is used to call two separate method will they still block each other?案例 4:假设 Demo 类
demo
和demo1
不同实例用于调用两个单独的方法,它们仍然会互相阻塞吗?
Case2 No, the lock is for method's object. Case2 不,锁是方法的对象。 Each instance keeps a separate lock
每个实例都有一个单独的锁
Case3 Yes, the static method has association with a class not a object, so the lock is for the Class
object. Case3 是的,静态方法关联的是类而不是对象,所以锁是针对
Class
对象的。 They block each other他们互相阻止
Case4: Yes, since it's the class object, same result in invoking it on different instances Case4:是的,因为它是类对象,所以在不同的实例上调用它的结果相同
The synchronized
keyword on a method is in just about every relevant fashion simply syntax sugar.方法上的
synchronized
关键字几乎在所有相关方式中都是简单的语法糖。 So let's desugar this, that makes it more clear:因此,让我们对此进行脱糖,使其更加清晰:
class Test {
synchronized void foo() {
hello();
}
}
// desugars to:
class Test {
void foo() {
synchronized (this) {
hello();
}
}
}
And if we involve static:如果我们涉及静态:
class Test {
static synchronized void staticFoo() {
hello();
}
}
// desugars to:
class Test {
static void staticFoo() {
synchronized (Test.class) {
hello();
}
}
}
Now we just need to explain what synchronized()
does, and perhaps what Test.class
does.现在我们只需要解释
synchronized()
作用,也许还有Test.class
作用。
Every object in java is also a locking object. java中的每个对象也是一个锁定对象。 It basically works like this:
它基本上是这样工作的:
Thread
and is called monitor
.Thread
类型,称为monitor
。 It also has a second hidden, in accessible field int monitorCount;
int monitorCount;
. null
value for the monitor
field.monitor
字段的null
值开始。synchronized(expr) {
means one of three things: synchronized(expr) {
表示三件事之一:expr
currently has monitor == null
, then execute: monitor = Thread.currentThread(); monitorCount = 1;
expr
时找到的对象当前具有monitor == null
,则执行: monitor = Thread.currentThread(); monitorCount = 1;
monitor = Thread.currentThread(); monitorCount = 1;
, and enter the {}
block. {}
块。expr
currently has monitor == Thread.currentThread()
, then simply execute monitorCount++
and enter the block.expr
时找到的对象当前具有monitor == Thread.currentThread()
,则只需执行monitorCount++
并进入块。monitor
's value is some other thread), freeze this thread until monitor
is null
, then act as per the first rule.monitor
的值是某个其他线程),冻结该线程直到monitor
为null
,然后按照第一个规则进行操作。monitor
is null
simultaneously or other such shenanigans. monitor
为null
或其他此类恶作剧的结论。 In other words, if you actually wrote this code, it wouldn't work, because you don't get that '... but atomically' guarantee, but synchronized
does provide it.synchronized
确实提供了它。 Test.class
is an exotic but entire valid java construct. Test.class
是一个奇特但完整有效的 java 构造。 Try it:尝试一下:
In java, any class has exactly one instance of the class java.lang.Class
associated with it.在 java 中,任何类都只有一个与之关联的
java.lang.Class
类的实例。 Given any object you can get it using obj.getClass()
.给定任何对象,您都可以使用
obj.getClass()
获取它。 If you don't have an instance of a class, but you do know exactly what class you're talking about, the language construct ThatClass.class
will get you that instance just the same.如果您没有类的实例,但您确实知道您在谈论什么类,那么语言构造
ThatClass.class
将为您提供相同的实例。 Let's try it:让我们试试看:
public static void main(String[] args) {
Class<?> stringClass = String.class;
System.out.println(stringClass);
System.out.println("".getClass() == String.class); // 'true'.
}
Note that without custom classloaders, these instances are singletons.请注意,如果没有自定义类加载器,这些实例是单例。
This then explains static synchronized
: They're all locking on the exact class.这然后解释了
static synchronized
:它们都锁定在确切的类上。 Note that this class stuff doesn't inherit: If you have:请注意,此类内容不会继承:如果您有:
class Parent {
static synchronized void parentMethod() {}
}
class Child extends Parent {
static synchronized void childMethod() {}
}
Then thread A can be executing parentMethod whilst at the same time thread B is executing childMethod as they are locking on different objects.然后线程 A 可以执行 parentMethod 而同时线程 B 正在执行 childMethod 因为它们锁定在不同的对象上。 (namely,
Child.class
, and Parent.class
. (即
Child.class
和Parent.class
。
With that knowledge:有了这些知识:
Case2: No, instance1.monitor == threadA;
Case2:不,
instance1.monitor == threadA;
and instance2.monitor == threadB;
和
instance2.monitor == threadB;
, no problem. , 没问题。 They won't block each other.
他们不会互相阻拦。
Case 3: Yes, as there is only one Demo.class.monitor`, and that can only be threadA or threadB.情况 3:是的,因为只有一个 Demo.class.monitor`,并且只能是 threadA 或 threadB。 The one that it isn't, can't enter these methods and has to wait.
不是的,不能进入这些方法,必须等待。
Case 4: Same as 3.情况 4:同 3。
Here's a couple of examples to - hopefully - make it more obvious.这里有几个例子 - 希望 - 让它更明显。
First the Instance Demo:首先是实例演示:
/**
* Instance : the Threads run independently, synchronizing on the Instances
*/
import java.util.Random;
import java.util.stream.IntStream;
public final class Demo {
private final Random randomA = new Random();
private final Random randomB = new Random();
private void common(final String label, final Random random) {
IntStream.range(0, 10).forEach(n -> {
final String thread = Thread.currentThread().getName();
System.out.println(thread + " Method " + label + "-1 n=" + n);
try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}
System.out.println(thread + " Method " + label + "-2 n=" + n + "\n");
try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}
});
}
private synchronized void methodA() {common("A_", randomA);}
private synchronized void methodB() {common("_B", randomB);}
public static void main(final String[] args) {
final Demo demoB = new Demo();
new Thread(() -> new Demo().methodA(), "[Thread_Aa_]").start(); // Comment out
// new Thread(() -> demoB .methodA(), "[Thread__Ba]").start(); // Un-Comment
new Thread(() -> demoB .methodB(), "[Thread__Bb]").start();
}
}
And now, the Static Demo:现在,静态演示:
/**
* Static : the Threads block each other, synchronizing on the Class
* 3 & 4) methodA & methodB are never interrupted
* 3 & 4) calling static Methods from the Instance gives a Compiler Warning
* & actually executes DemoStatic.methodA(...) or DemoStatic.methodB(...)
* Warning:
* The static method x(.) from the type Y should be accessed in a static way
*/
import java.util.Random;
import java.util.stream.IntStream;
public final class DemoStatic {
private static final Random randomA = new Random();
private static final Random randomB = new Random();
private static void common(final String label, final Random random, final int n) {
final String thread = Thread.currentThread().getName();
System.out.println(thread + " Method " + label + "-1 n=" + n);
try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}
System.out.println(thread + " Method " + label + "-2 n=" + n + "\n");
try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}
}
public static synchronized void methodA(final int n) {common("A_", randomA, n);}
public static synchronized void methodB(final int n) {common("_B", randomB, n);}
public static void main(final String[] args) {
// @SuppressWarnings("static-access")
final Runnable loopA = () -> IntStream.range(0, 10).forEach(n -> new DemoStatic().methodA(n));
final Runnable loopB = () -> IntStream.range(0, 10).forEach(n -> DemoStatic .methodB(n));
new Thread(loopA, "[Thread_A_]").start();
new Thread(loopB, "[Thread__B]").start();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.