嵌套同步块的缺点
Disadvantages of nested synchronized blocks
学习线程和并发。考虑以下代码:
class A {
protected final Object lock = new Object();
public void remove(Object obj){
synchronized(lock){
// remove the object
}
}
public void add(Object obj){
synchronized(lock){
// add the object
}
}
}
这段代码是线程安全的,因为没有两个不同的线程可以 add
或 remove
而一个线程正在添加或删除。
现在考虑 A 的以下子类:
class B extends A {
public void update1(Object original, Object newObj){
remove(original);
add(original);
}
public void update2(Object original, Object newObj){
synchronized(lock) {
remove(original);
add(newObj);
}
}
}
Class B
必须实现线程安全的 update
方法。现在,据我所知 update1
不是线程安全的,因为该操作不是原子的,即 remove
和 add
的执行之间没有同步(如果错误请纠正我)。
update2
是实现线程安全 update
方法的正确方法吗?
在同一个 lock
上嵌套同步块有什么缺点吗?
Is update2
the correct way to implement a thread-safe update method?
是的,是的。您已经实现了原子性,并且与个别 add
和 remove
方法的调用者兼容。
Are there any disadvantages of having nested synchronized blocks over the same lock?
否,因为锁是 可重入的,这意味着第二次获取除了记住锁已被再次获取外什么都不做,所以它不会被释放直到执行了两个 release 操作。
使用synchronized
使得整个对象"locked": 没有其他线程可以调用任何方法,而另一个线程是运行对象同步方法之一。
这种行为确实会使某些程序变慢。
作为替代方法,您可以使用 ReentrantLock
。
下面是如何应用 post 中的代码:
class A {
protected final Lock lock = new ReentrantLock();
public void remove(Object obj){
lock.lock();
try {
// remove the object
} finally {
lock.unlock();
}
}
public void add(Object obj){
lock.lock();
try {
// add the object
} finally {
lock.unlock();
}
}
}
class B extends A {
// ...
public void update2(Object original, Object newObj){
lock.lock();
try {
remove(original);
add(newObj);
} finally {
lock.unlock();
}
}
}
锁是可重入的,除非你会在每个地方看到死锁
重入锁是即使同一个线程已经获得了锁,也可以重新获取的锁。
为什么你不在 Super class 方法中提供 removeAndAdd ,如果有一个场景必须有 remove 和 add atomic 。
出于安全原因,确保您的锁对象被标记为私有和最终。
学习线程和并发。考虑以下代码:
class A {
protected final Object lock = new Object();
public void remove(Object obj){
synchronized(lock){
// remove the object
}
}
public void add(Object obj){
synchronized(lock){
// add the object
}
}
}
这段代码是线程安全的,因为没有两个不同的线程可以 add
或 remove
而一个线程正在添加或删除。
现在考虑 A 的以下子类:
class B extends A {
public void update1(Object original, Object newObj){
remove(original);
add(original);
}
public void update2(Object original, Object newObj){
synchronized(lock) {
remove(original);
add(newObj);
}
}
}
Class B
必须实现线程安全的 update
方法。现在,据我所知 update1
不是线程安全的,因为该操作不是原子的,即 remove
和 add
的执行之间没有同步(如果错误请纠正我)。
update2
是实现线程安全 update
方法的正确方法吗?
在同一个 lock
上嵌套同步块有什么缺点吗?
Is
update2
the correct way to implement a thread-safe update method?
是的,是的。您已经实现了原子性,并且与个别 add
和 remove
方法的调用者兼容。
Are there any disadvantages of having nested synchronized blocks over the same lock?
否,因为锁是 可重入的,这意味着第二次获取除了记住锁已被再次获取外什么都不做,所以它不会被释放直到执行了两个 release 操作。
使用synchronized
使得整个对象"locked": 没有其他线程可以调用任何方法,而另一个线程是运行对象同步方法之一。
这种行为确实会使某些程序变慢。
作为替代方法,您可以使用 ReentrantLock
。
下面是如何应用 post 中的代码:
class A {
protected final Lock lock = new ReentrantLock();
public void remove(Object obj){
lock.lock();
try {
// remove the object
} finally {
lock.unlock();
}
}
public void add(Object obj){
lock.lock();
try {
// add the object
} finally {
lock.unlock();
}
}
}
class B extends A {
// ...
public void update2(Object original, Object newObj){
lock.lock();
try {
remove(original);
add(newObj);
} finally {
lock.unlock();
}
}
}
锁是可重入的,除非你会在每个地方看到死锁
重入锁是即使同一个线程已经获得了锁,也可以重新获取的锁。
为什么你不在 Super class 方法中提供 removeAndAdd ,如果有一个场景必须有 remove 和 add atomic 。
出于安全原因,确保您的锁对象被标记为私有和最终。