由于Java的同步概念,我感到非常困惑。
让我们假设以下课程:
class MyClass {
public synchronized void foo() { //do something }
public void bar() {
synchronized(this) { //do something }
}
public void normal() { //do something }
}
据我所知,foo
和bar
方法的工作原理相同。
但是,在线程A进入bar
方法并通过synchronized(this)
同步实例之后,任何线程都可以调用普通方法吗?
据我所知,某些线程可以调用普通方法,而无需调用foo
方法。但是我不确定何时调用bar
方法,因为它同步了一个实例。
此外,我们假设采用以下方法:
class StaticMyClass {
public static synchronized void fooStatic() { //do something }
publi static void barStatic() {
synchronized(StaticMyClass.class) { //do something }
}
public static void normalStatic() { //do something }
}
在这里,有相同的问题。线程A进入临界区(为synchronized(StaticMyClass.class)
或fooStatic
方法之后,任何线程都可以调用normalStatic
吗?
我认为fooStatic
和normalStatic
可以独立调用,而barStatic
和normalStatic
则不能。如果不对,为什么?
感谢您的帮助。
修改:
我的困惑点是我不确定synchronized(this)
是否与synchronized(myClassInstance)
相同。
MyClass my = new MyClass();
synchronized(my) {
//do something, Any other thread can't access my.normal(), is it right?
}
class MyClass {
public synchronized void foo() { //do something }
public void bar() {
synchronized(this) {
//do something, isn't this same as above synchronized(my)?
}
}
public void normal() { //do something }
}
答案 0 :(得分:2)
据我所知,
foo
和bar
方法的工作原理相同。
正确。它们都在this
上进行同步。
线程A输入
bar
方法并通过synchronized(this)
同步实例后,任何线程都可以调用normal
方法吗?
是的。正确。
据我所知,某些线程可以调用
normal
方法,而无需调用foo
方法。但是我不确定何时调用bar方法。因为它同步了一个实例。
foo
和bar
相同。它们都在this
上同步。 normal
方法未对任何内容进行同步。因此,可以随时随地调用它,并且在方法调用时或在内部都不会阻塞。
在您的术语中,normal
方法不是关键部分 1 。
第二个带有静力学的例子
在这里,有同样的问题。在线程A进入临界部分(是
synchronized(StaticMyClass.class)
或fooStatic
方法之后,任何线程都可以调用normalStatic
吗?
是的。 fooStatic
和barStatic
都将在StaticMyClass.class
上进行同步。
我认为,可以分别调用
fooStatic
和normalStatic
,但不能分别调用barStatic
和normalStatic
。
不正确。 normalStatic
未被fooStatic
或barStatic
阻止。
我不确定您在哪里知道normalStatic
可能会被阻止……但是这是一个普通的方法调用,并且不会获取任何内部锁,因此无法在锁上对其进行阻止。
您的第三个示例尚不清楚。代码显示了一件事,但是问题提出了不同/不相关的问题。
1-如果(例如)foo
或bar
在保持固有锁定的同时被称为normal
,可能会造成一些混乱。然后normal
代码将有效地放在关键部分,因为调用者持有该锁。但是它(normal
)通常不知道这一点。这就是为什么我更喜欢避免使用“关键部分”的术语。
答案 1 :(得分:1)
如果未指定监视器是谁,则使用实例方法,监视器是实例(this),使用静态方法,监视器是类(YourClass.class)。
此代码
public synchronized void foo() { //do something }
与此相同
public void foo() {
synchronized(this) { //do something }
}
和此代码
public static synchronized void fooStatic() { //do something }
与此相同
public static void fooStatic() {
synchronized(StaticMyClass.class) { //do something }
}
因此,在两种情况下,foo和bar都是依赖的(同时只能有一个线程),而normal可以独立调用。
答案 2 :(得分:1)
但是在线程A进入bar方法并通过Synchronized(this)同步实例之后,任何线程都可以调用普通方法吗?
在同一对象上两次同步方法的调用是不可能交织的。当一个线程正在执行对象的同步方法时,所有其他为同一对象块调用同步方法的线程(挂起执行),直到第一个线程对该对象完成为止。
如果您尝试调用其他不同步的方法,则可以。
在线程A进入已同步(StaticMyClass.class)或fooStatic方法的关键部分之后,任何线程都可以调用normalStatic吗? 我认为,可以分别调用fooStatic和normalStatic,但不能单独调用barStatic和normalStatic。如果错了为什么?
可以同步调用其他未同步的方法,但是当您调用barStatic()时,由于正在同步整个类,因此无法调用其他方法。其他线程,必须等到当前线程完成执行。