我已开始在线程中学习同步。
同步方法:
public class Counter{
private static int count = 0;
public static synchronized int getCount(){
return count;
}
public synchronized setCount(int count){
this.count = count;
}
}
同步块:
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;
}
我应该何时使用Synchronized方法和Synchronized块? 为什么Synchronized阻止比同步方法更好?
答案 0 :(得分:67)
这不是更好,只是不同。
同步方法时,您实际上正在同步对象本身。对于静态方法,您将同步到对象的类。所以以下两段代码执行相同的方式:
public synchronized int getCount() {
// ...
}
这就像你写的那样。
public int getCount() {
synchronized (this) {
// ...
}
}
如果要控制与特定对象的同步,或者只希望将方法的 part 同步到该对象,请指定synchronized
块。如果在方法声明中使用synchronized
关键字,它会将整个方法与对象或类同步。
答案 1 :(得分:34)
虽然通常不是一个问题,但从安全角度来看,最好在私有对象上使用synchronized,而不是将其放在方法上。
将它放在方法上意味着您正在使用对象本身的锁来提供线程安全性。使用这种机制,您的代码的恶意用户也可能获得对象的锁定,并永久保留它,有效地阻止其他线程。非恶意用户可以无意中有效地做同样的事情。
如果使用私有数据成员的锁定,则可以阻止此操作,因为恶意用户无法获取私有对象的锁定。
private final Object lockObject = new Object();
public void getCount() {
synchronized( lockObject ) {
...
}
}
Bloch的Effective Java(第2版),第70项
中提到了这种技术答案 2 :(得分:21)
区别在于获取锁定:
synchronized方法获取整个对象的锁定。这意味着当该方法由一个线程运行时,没有其他线程可以在整个对象中使用任何同步方法。
synchronized块在synchronized关键字后获取括号内对象的锁定。这意味着在同步块退出之前,没有其他线程可以锁定锁定的对象。
因此,如果要锁定整个对象,请使用synchronized方法。如果要将对象的其他部分保持为其他线程可访问,请使用synchronized块。
如果仔细选择锁定对象,同步块将导致争用较少,因为整个对象/类未被阻止。
这同样适用于静态方法:同步静态方法将获取整个类对象中的锁定,而静态方法中的同步块将获取括号内对象的锁定。
答案 3 :(得分:6)
同步块与同步方法的区别如下:
synchronized block:
synchronized(this){}
同步方法:
public synchronized void fun(){}
答案 4 :(得分:5)
定义'更好'。同步块只有更好,因为它允许您:
现在您的具体示例是可疑的double-checked locking模式的示例(在较旧的Java版本中,它被破坏,并且很容易做错)。
如果您的初始化很便宜,最好立即使用final字段进行初始化,而不是第一次请求,这也可以消除同步的需要。
答案 5 :(得分:2)
在你的情况下两者都是等价的! strong>
同步静态方法相当于相应Class对象上的synchronized块。
实际上,当您在与Class对象相对应的监视器上声明同步静态方法锁定时。
public static synchronized int getCount() {
// ...
}
与
相同public int getCount() {
synchronized (ClassName.class) {
// ...
}
}
答案 6 :(得分:2)
同步。事实上,大多数类都不应该使用同步。 同步方法只会在此对象上提供 lock ,并且仅在执行期间提供。如果你真的想让你的课程线程安全,你应该考虑让你的变量不稳定或同步访问。
使用同步方法的一个问题是,该类的所有成员都会使用相同的 lock ,这会使您的程序变慢。在你的情况下,synchronized方法和块将执行没有不同。我建议使用专用的锁并使用 synchronized块这样的内容。
public class AClass {
private int x;
private final Object lock = new Object(); //it must be final!
public void setX() {
synchronized(lock) {
x++;
}
}
}
答案 7 :(得分:1)
因为锁是昂贵的,所以当你使用同步块时,只有在_instance == null
时锁定,并且在_instance
最终初始化之后你永远不会锁定。但是,当您在方法上进行同步时,即使在_instance
初始化之后,您也会无条件地锁定。这是双重检查锁定优化模式http://en.wikipedia.org/wiki/Double-checked_locking背后的想法。
答案 8 :(得分:1)
它不应被视为最佳使用问题,但它实际上取决于用例或场景。
同步方法
整个方法可以标记为synchronized,从而导致对此引用(实例方法)或类(静态方法)的隐式锁定。这是实现同步的非常方便的机制。
<强>步骤强> 线程访问synchronized方法。它隐式获取锁并执行代码。 如果其他线程想要访问上述方法,则必须等待。线程无法获得锁定,将被阻止并且必须等到锁定被释放。
同步阻止
要获取特定代码块对象的锁定,同步块最适合。由于块足够,使用同步方法将是一种浪费。
更具体地说,使用同步块,可以定义想要获取锁定的对象引用。
答案 9 :(得分:0)
同步块与同步方法之间的经典区别是同步方法锁定整个对象。同步块只是将代码锁定在该块内。
同步方法:基本上这两个同步方法禁用多线程。因此,一个线程完成method1(),而另一个线程等待Thread1完成。
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");
}
}
}
在方法1中
最后是方法1
方法2 1
方法2 2
方法2 3
方法2 4
方法2 5
方法2 6
方法2 7
方法2 8
方法2 9
最后是方法2
同步块:允许多个线程同时访问同一对象[启用多线程]。
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");
}
}
}
}
在方法1中
方法2 1
方法2 2
方法2 3
方法2 4
方法2 5
最后是方法1
方法2 6
方法2 7
方法2 8
方法2 9
最后是方法2