我已经阅读了很多关于Java对象级别同步的教程。而我所理解的是,每当线程调用同步方法/块时,它将获取方法对象的锁定并在执行后释放。因此,在锁定时,没有其他线程可以访问相同的对象数据。 但是当我尝试下面的场景时,发现其他线程可以并行访问锁定对象的非同步方法。
class A {
public synchronized void test1(){}
public void test2(){}
}
我创建了3个帖子t1
,t2
和t3
。并且所有都引用了类A的相同对象.t1正在调用test1()
,而另外两个线程正在调用test2()
。
在这里,我可以看到test1()
正在执行时,t2
和t3
个线程test2()
也会并行运行。
所以我的问题是同步是否真的完全锁定了一个对象,或者只是锁定了特定的同步方法?如果是这样,为什么它调用对象级锁定。
在班级锁定的情况下会发生什么?
答案 0 :(得分:1)
同步确保任何需要在 synchronized 块中执行代码块的线程首先必须获取Object的监视器(在块内部的代码执行开始之前锁定)。因此,当一个线程在同步块内执行代码时,尝试执行相同或其他同步块的其他线程(在同一对象上,即相同的 lock )将必须等到它们获得锁定。
允许其他线程在非同步的代码块中执行代码,因为这并不涉及获取监视器/锁定。请注意,如果需要获取不同的锁,其他线程甚至可以执行 synchronized blocks 中的代码。
答案 1 :(得分:0)
如果其他线程尝试执行任何其他已同步的方法,则需要获取锁定。他们可以自由地调用其他没有synchronized关键字的方法(即使锁被一些线程获取),因为调用它们不需要获取锁定/监视器。
答案 2 :(得分:0)
显式锁定对象(例如A
的实例)与A
类中声明的内部锁定习语之间存在差异。
在您的情况下,方法test1
是实例同步的,这意味着对于给定的A
实例,当时只有一个线程可以调用它。
但是,test2
未同步,因此任何给定时间的任何线程都可以在理论上调用它。
现在,如果你synchronized(myAInstance)
,那么一旦获得锁,只有synchronized
语句中的执行代码才能调用你{{1}的任何方法实例,直到锁被释放。
答案 3 :(得分:0)
你真的搞混了什么。
class A {
public synchronized void test1(){}
public void test2(){}
}
这将创建对test1方法的同步访问。这意味着,只有一个并行线程可以执行该方法。如果你想拥有一个锁定方法,你可以创建自己的锁对象:
class A {
private static final Object myLock= new Object();
public void test1(){
synchronized (myLock){
}
}
public void test2(){
synchronized (myLock){
}
}
}
如果您的应用程序中的任何其他人使用相同的对象,您的线程也会被阻止。通常你定义一种每个人都遵循的锁对象结构。
答案 4 :(得分:0)
虽然在许多情况下将同步视为排除的方法可能是合适的,但还有另一种方法可以将其视为对其他人更具说明性,并且这就是可见性的想法。
退出同步块意味着所有更改都会提交回内存。 输入同步块可确保您对其将要访问的内存所做的所有更改都可以正常显示。
如果你认为同步是一种在你做东西的时候锁定他人的方法,你需要把它想象成一个“占用” - 而不是门锁:它只能由其他人礼貌你可以独处 - 也就是说,如果他们也使用相同的同步机制。考虑可见性可以更容易地理解为什么有礼貌才能获得回报。
在您的情况下,当然,test1
和test2
方法都必须标记为“已同步”。这与将A对象用作锁定相同。
更进一步,我非常想鼓励您查看java.util.concurrent
- 包及其子包atomic
和locks
。您想要实现的大部分内容已经在那里实现,使用这些库可以让您更轻松,更安全。它还使您的代码更易于维护和阅读。
答案 5 :(得分:0)
制作这些方法
top
有两个影响:首先,对同一对象的两个
synchronized
方法的调用不可能进行交错。当一个线程正在为一个对象执行synchronized
方法时,所有其他线程都会为同一个对象阻塞synchronized
方法(暂停执行),直到第一个线程完成该对象为止。
=>在任何时候,您都无法并行执行同一对象上的两个synchronized
方法。
回到您的查询:
synchronized
test1()
而synchronized
不是。
test2()
因此它们可以并行运行。
如果您将T1 execution of test1() and T2 & T3 exection of test2() does not break above rule
更改为test2()
方法,事情就会发生变化。
在这种情况下,在synchronized
完成它T1
的执行之前,test1()
必须等到T2 and T3
完成它的执行。 T1
完成执行后,T1
之一可以调用T2 or T3
方法。