Java中的同步方法和同步块有什么区别?
我一直在网上搜索答案,人们似乎对此不太确定:-(
我的看法是两者之间没有区别,只是同步块可能在范围内更加本地化,因此锁定时间会更短?
如果在静态方法上使用 Lock,那么 Lock 是在什么情况下使用的?Lock on Class 是什么意思?
Java中的同步方法和同步块有什么区别?
我一直在网上搜索答案,人们似乎对此不太确定:-(
我的看法是两者之间没有区别,只是同步块可能在范围内更加本地化,因此锁定时间会更短?
如果在静态方法上使用 Lock,那么 Lock 是在什么情况下使用的?Lock on Class 是什么意思?
同步方法使用方法接收器作为锁(即this
用于非静态方法,以及用于静态方法的封闭类)。 Synchronized
blocks 使用表达式作为锁。
因此,从锁定角度来看,以下两种方法是等效的:
synchronized void mymethod() { ... }
void mymethod() {
synchronized (this) { ... }
}
对于静态方法,类将被锁定:
class MyClass {
synchronized static mystatic() { ... }
static mystaticeq() {
syncrhonized (MyClass.class) { ... }
}
}
对于同步块,您可以使用任何非null
对象作为锁:
synchronized (mymap) {
mymap.put(..., ...);
}
锁定范围
对于同步方法,锁将在整个方法范围内保持,而在synchronized
块中,锁仅在该块范围内(也称为临界区)保持。synchronized
在实践中,如果 JVM可以证明可以安全地完成,则允许通过从块执行中删除一些操作来进行优化。
同步方法是简写。这个:
class Something {
public synchronized void doSomething() {
...
}
public static synchronized void doSomethingStatic() {
...
}
}
就所有意图和目的而言,等同于:
class Something {
public void doSomething() {
synchronized(this) {
...
}
}
public static void doSomethingStatic() {
synchronized(Something.class) {
...
}
}
}
Something.class
(类的类对象在哪里Something
。)
因此,确实,使用同步块,您可以更具体地了解您的锁,并且更细粒度地了解何时使用它,但除此之外没有任何区别。
是的,这是一个区别。另一个是您可以获取除 之外的其他对象的锁this
。
关键的区别在于:如果你声明一个方法是同步的,那么整个方法体就会同步;但是,如果您使用同步块,那么您可以只将方法的“关键部分”包含在同步块中,而将方法的其余部分留在块之外。
如果整个方法是关键部分的一部分,那么实际上没有区别。如果不是这种情况,那么您应该只在关键部分周围使用同步块。同步块中的语句越多,获得的整体并行度就越少,因此您希望将这些语句保持在最低限度。
同步方法锁定包含该方法的对象实例。
同步块可以锁定任何对象 - 通常是定义为实例变量的互斥对象。这允许更多地控制正在运行的锁。
我的看法是两者之间没有区别,只是同步块可能在范围内更加本地化,因此锁定时间会更短?
是的。你说的对。与synchronized
方法不同,同步语句必须指定提供内在锁的对象。
java教程中的示例:
public void addName(String name) {
synchronized(this) {
lastName = name;
nameCount++;
}
nameList.add(name);
}
同步语句对于通过细粒度同步提高并发性也很有用。您可以在以下用例的同一教程页面上找到很好的示例。
例如,假设类MsLunch
有两个从不一起使用的实例字段 c1 和 c2。这些字段的所有更新都必须是synchronized
,但没有理由阻止 c1 的更新与 c2 的更新交错 - 这样做会通过创建不必要的阻塞来降低并发性。我们不使用同步方法或以其他方式使用与此关联的锁,而是创建两个对象来提供锁。
如果在静态方法上使用 Lock,那么 Lock 是在什么情况下使用的?Lock on Class 是什么意思?
在这种情况下,线程获取与该类关联的 Class 对象的内在锁。因此,对类的静态字段的访问由与类的任何实例的锁不同的锁控制。
当您将方法设为同步(非static
)时:
synchronized
对同一对象的两次方法调用不可能交错。当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。
如果您将方法设为static synchronized
:
static synchronized
对同一类的不同对象的两次方法调用不可能交错。当一个线程正在执行static synchronized
A 类对象的方法时,所有其他调用 A 类对象的方法的所有其他线程都会static synchronized
阻塞(暂停执行),直到第一个线程完成方法执行。
您可以在这个 SE 问题中找到更好的同步替代方案: