Java 为什么同步块比同步方法更好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20906548/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is synchronized block better than synchronized method?
提问by Sabapathy
I have started learning synchronization in threading.
我已经开始学习线程同步。
Synchronized method:
同步方法:
public class Counter {
private static int count = 0;
public static synchronized int getCount() {
return count;
}
public synchronized setCount(int count) {
this.count = count;
}
}
Synchronized block:
同步块:
public class Singleton {
private static volatile Singleton _instance;
public static Singleton getInstance() {
if (_instance == null) {
synchronized(Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
When should I use synchronized
method and synchronized
block?
什么时候应该使用synchronized
方法和synchronized
块?
Why is synchronized
block better than synchronized
method ?
为什么synchronized
block 比synchronized
method 好?
采纳答案by Erick Robertson
It's not a matter of better, just different.
这不是更好的问题,只是不同。
When you synchronize a method, you are effectively synchronizing to the object itself. In the case of a static method, you're synchronizing to the class of the object. So the following two pieces of code execute the same way:
当您同步一个方法时,您实际上是在同步到对象本身。在静态方法的情况下,您正在同步到对象的类。所以下面两段代码的执行方式是一样的:
public synchronized int getCount() {
// ...
}
This is just like you wrote this.
这就像你写的一样。
public int getCount() {
synchronized (this) {
// ...
}
}
If you want to control synchronization to a specific object, or you only want partof a method to be synchronized to the object, then specify a synchronized
block. If you use the synchronized
keyword on the method declaration, it will synchronize the whole method to the object or class.
如果要控制与特定对象的同步,或者只想将方法的一部分同步到该对象,则指定一个synchronized
块。如果synchronized
在方法声明中使用关键字,它将使整个方法同步到对象或类。
回答by Aniket Thakur
In your case both are equivalent!
在你的情况下,两者都是等价的!
Synchronizing a static method is equivalent to a synchronized block on corresponding Class object.
同步一个静态方法相当于在相应的 Class 对象上同步一个块。
In fact when you declare a synchronized static method lock is obtained on the monitor corresponding to the Class object.
实际上当你声明一个synchronized静态方法时,是在Class对象对应的monitor上获得锁的。
public static synchronized int getCount() {
// ...
}
is same as
与
public int getCount() {
synchronized (ClassName.class) {
// ...
}
}
回答by Mark Rotteveel
Define 'better'. A synchronized block is only better because it allows you to:
定义“更好”。同步块只是更好,因为它允许您:
- Synchronize on a different object
- Limit the scope of synchronization
- 在不同的对象上同步
- 限制同步范围
Now your specific example is an example of the double-checked lockingpattern which is suspect (in older Java versions it was broken, and it is easy to do it wrong).
现在,您的具体示例是可疑的双重检查锁定模式的示例(在较旧的 Java 版本中,它已损坏,并且很容易出错)。
If your initialization is cheap, it might be better to initialize immediately with a final field, and not on the first request, it would also remove the need for synchronization.
如果您的初始化成本较低,最好立即使用 final 字段进行初始化,而不是在第一次请求时进行初始化,这也将消除同步的需要。
回答by Ashish
synchronizedshould only be used when you want your class to be Thread safe. In fact most of the classes should not use synchronized anyways. synchronizedmethod would only provide a lockon this object and only for the duration of its execution. if you really wanna to make your classes thread safe, you should consider making your variables volatileor synchronizethe access.
仅当您希望您的类是线程安全的时才应使用同步。事实上,大多数类无论如何都不应该使用同步。同步方法只会在此对象上提供锁定,并且仅在其执行期间提供锁定。如果你真的想让你的类线程安全,你应该考虑让你的变量可变或同步访问。
one of the issues of using synchronized methodis that all of the members of the class would use the same lockwhich will make your program slower. In your case synchronized method and block would execute no different. what I'd would recommend is to use a dedicated lockand use a synchronized blocksomething like this.
使用同步方法的问题之一是该类的所有成员都将使用相同的锁,这会使您的程序变慢。在您的情况下,同步方法和块将执行没有什么不同。我会推荐的是使用专用锁并使用类似这样的同步块。
public class AClass {
private int x;
private final Object lock = new Object(); //it must be final!
public void setX() {
synchronized(lock) {
x++;
}
}
}
回答by Evgeniy Dorofeev
Because lock is expensive, when you are using synchronized block you lock only if _instance == null
, and after _instance
finally initialized you'll never lock. But when you synchronize on method you lock unconditionally, even after the _instance
is initialized. This is the idea behind double-checked locking optimization pattern http://en.wikipedia.org/wiki/Double-checked_locking.
因为锁定是昂贵的,当你使用同步块时,你只锁定 if _instance == null
,并且在_instance
最终初始化之后你永远不会锁定。但是当您同步方法时,您会无条件锁定,即使在_instance
初始化之后也是如此。这是双重检查锁定优化模式http://en.wikipedia.org/wiki/Double-checked_locking背后的想法。
回答by wolfcastle
Although not usually a concern, from a security perspective, it is better to use synchronized on a private object, rather than putting it on a method.
虽然通常不是一个问题,但从安全角度来看,最好在私有对象上使用同步,而不是将它放在方法上。
Putting it on the method means you are using the lock of the object itself to provide thread safety. With this kind of mechanism, it is possible for a malicious user of your code to also obtain the lock on your object, and hold it forever, effectively blocking other threads. A non-malicious user can effectively do the same thing inadvertently.
将它放在方法上意味着您正在使用对象本身的锁来提供线程安全。通过这种机制,您代码的恶意用户也有可能获得您对象的锁,并永久持有它,从而有效地阻塞其他线程。非恶意用户可以在不经意间有效地做同样的事情。
If you use the lock of a private data member, you can prevent this, since it is impossible for a malicious user to obtain the lock on your private object.
如果您使用私有数据成员的锁,则可以防止这种情况发生,因为恶意用户不可能获得您私有对象的锁。
private final Object lockObject = new Object();
public void getCount() {
synchronized( lockObject ) {
...
}
}
This technique is mentioned in Bloch's Effective Java (2nd Ed), Item #70
Bloch 的 Effective Java(第 2 版)第 70 项中提到了这种技术
回答by Angular University
The difference is in which lock is being acquired:
不同之处在于获取的是哪个锁:
synchronized method acquires a lock on the whole object. This means no other thread can use any synchronized method in the whole object while the method is being run by one thread.
synchronized blocks acquires a lock in the object between parentheses after the synchronized keyword. Meaning no other thread can acquire a lock on the locked object until the synchronized block exits.
同步方法获取整个对象的锁。这意味着当一个线程正在运行该方法时,没有其他线程可以在整个对象中使用任何同步方法。
synchronized 块在synchronized 关键字之后的括号之间获取对象中的锁。这意味着在同步块退出之前,没有其他线程可以获取锁定对象的锁定。
So if you want to lock the whole object, use a synchronized method. If you want to keep other parts of the object accessible to other threads, use synchronized block.
因此,如果您想锁定整个对象,请使用同步方法。如果您想让其他线程可以访问对象的其他部分,请使用同步块。
If you choose the locked object carefully, synchronized blocks will lead to less contention, because the whole object/class is not blocked.
如果仔细选择锁定的对象,同步块将导致较少的争用,因为整个对象/类都没有被阻塞。
This applies similarly to static methods: a synchronized static method will acquire a lock in the whole class object, while a synchronized block inside a static method will acquire a lock in the object between parentheses.
这同样适用于静态方法:同步静态方法将获取整个类对象中的锁,而静态方法内的同步块将获取括号之间对象中的锁。
回答by Sameera
It should not be considered as a question of best for usage, but it really depends on the use case or the scenario.
不应将其视为最佳使用问题,但它确实取决于用例或场景。
Synchronized Methods
同步方法
An entire method can be marked as synchronized resulting an implicit lock on the this reference (instance methods) or class (static methods). This is very convenient mechanism to achieve synchronization.
可以将整个方法标记为同步,从而导致对 this 引用(实例方法)或类(静态方法)的隐式锁定。这是实现同步的非常方便的机制。
StepsA thread access the synchronized method. It implicitly acquires the lock and execute the code. If other thread want to access the above method, it has to wait. The thread can't get the lock, will be blocked and has to wait till the lock is released.
步骤线程访问同步方法。它隐式地获取锁并执行代码。如果其他线程要访问上述方法,则必须等待。线程无法获得锁,将被阻塞,必须等到锁被释放。
Synchronized Blocks
同步块
To acquire a lock on an object for a specific set of code block, synchronized blocks are the best fit. As a block is sufficient, using a synchronized method will be a waste.
要为一组特定的代码块获取对象上的锁,同步块是最合适的。由于一个块就足够了,使用同步方法将是一种浪费。
More specifically with Synchronized Block , it is possible to define the object reference on which are want to acquire a lock.
更具体地说,使用 Synchronized Block ,可以定义要获取锁的对象引用。
回答by Raman Gupta
Difference between synchronized blockand synchronized methodare following:
同步块和同步方法的区别如下:
- synchronized block reduce scope of lock, butsynchronized method's scope of lock is whole method.
- synchronized block has better performance as only the critical section is locked butsynchronized method has poor performance than block.
- synchronized block provide granular control over lock butsynchronized method lock either on current object represented by this or class level lock.
- synchronized block can throw NullPointerException butsynchronized method doesn't throw.
synchronized block:
synchronized(this){}
synchronized method:
public synchronized void fun(){}
- 同步块减少了锁的范围,但同步方法的锁范围是整个方法。
- 同步块具有更好的性能,因为只有临界区被锁定,但同步方法的性能比块差。
- 同步块提供对锁的细粒度控制,但同步方法锁定由 this 或类级锁表示的当前对象。
- 同步块可以抛出 NullPointerException但同步方法不会抛出。
同步块:
synchronized(this){}
同步方法:
public synchronized void fun(){}
回答by Sri
One classic difference between Synchronized block and Synchronized method is that Synchronized method locks the entire object. Synchronized block just locks the code within the block.
Synchronized 块和 Synchronized 方法之间的一个经典区别是 Synchronized 方法锁定整个对象。同步块只是锁定块内的代码。
Synchronized method: Basically these 2 sync methods disable multithreading. So one thread completes the method1() and the another thread waits for the Thread1 completion.
同步方法:基本上这两种同步方法禁用多线程。所以一个线程完成method1(),另一个线程等待Thread1 完成。
class SyncExerciseWithSyncMethod {
类 SyncExerciseWithSyncMethod {
public synchronized void method1() {
try {
System.out.println("In Method 1");
Thread.sleep(5000);
} catch (Exception e) {
System.out.println("Catch of method 1");
} finally {
System.out.println("Finally of method 1");
}
}
public synchronized void method2() {
try {
for (int i = 1; i < 10; i++) {
System.out.println("Method 2 " + i);
Thread.sleep(1000);
}
} catch (Exception e) {
System.out.println("Catch of method 2");
} finally {
System.out.println("Finally of method 2");
}
}
}
}
Output
输出
In Method 1
在方法 1 中
Finally of method 1
方法一的最后
Method 2 1
方法 2 1
Method 2 2
方法 2 2
Method 2 3
方法 2 3
Method 2 4
方法 2 4
Method 2 5
方法 2 5
Method 2 6
方法 2 6
Method 2 7
方法 2 7
Method 2 8
方法 2 8
Method 2 9
方法 2 9
Finally of method 2
方法二的最后
Synchronized block: Enables multiple threads to access the same object at same time [Enables multi-threading].
同步块:允许多个线程同时访问同一个对象【启用多线程】。
class SyncExerciseWithSyncBlock {
类 SyncExerciseWithSyncBlock {
public Object lock1 = new Object();
public Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
try {
System.out.println("In Method 1");
Thread.sleep(5000);
} catch (Exception e) {
System.out.println("Catch of method 1");
} finally {
System.out.println("Finally of method 1");
}
}
}
public void method2() {
synchronized (lock2) {
try {
for (int i = 1; i < 10; i++) {
System.out.println("Method 2 " + i);
Thread.sleep(1000);
}
} catch (Exception e) {
System.out.println("Catch of method 2");
} finally {
System.out.println("Finally of method 2");
}
}
}
}
}
Output
输出
In Method 1
在方法 1 中
Method 2 1
方法 2 1
Method 2 2
方法 2 2
Method 2 3
方法 2 3
Method 2 4
方法 2 4
Method 2 5
方法 2 5
Finally of method 1
方法一的最后
Method 2 6
方法 2 6
Method 2 7
方法 2 7
Method 2 8
方法 2 8
Method 2 9
方法 2 9
Finally of method 2
方法二的最后