我有一个示例类:
public class LocksAndSynchronization {
private Object lock1 = new Object();
private Object lock2 = new Object();
static int count;
public void methodOne() {
for (int i = 1; i <= 10000; i++) {
count++;
}
}
public void methodTwo() {
for (int i = 1; i <= 10000; i++) {
count++;
}
}
public synchronized void process() {
methodOne();
methodTwo();
}
public static void main(String[] args) throws InterruptedException {
final LocksAndSynchronization l = new LocksAndSynchronization();
Thread t1 = new Thread() {
@Override
public void run() {
l.process();
}
};
Thread t2 = new Thread() {
@Override
public void run() {
l.process();
}
};
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("count: " + count);
}
}
process()实际上调用了这两个方法。那么这是一种更好的方法呢?
methodOne
和methodTwo
或process()
(如上面的代码所示)?以上两个选项都可行。但是哪一个更有意义?
答案 0 :(得分:3)
count是静态的,因此对于所有对象都是相同的。所以你需要同步进程静态方式。要做到这一点,创建一个静态锁并使用它
static Object staticObject = new Object();
public void process() {
synchronized( staticObject){
methodOne();
methodTwo();
}
}
或者你可以同步methodOne和methodTwo
static Object staticObject = new Object();
public void methodOne() {
synchronized( staticObject){
for (int i = 1; i <= 10000; i++) {
count++;
}
}
}
public void methodTwo() {
synchronized( staticObject){
for (int i = 1; i <= 10000; i++) {
count++;
}
}
}
此外,在函数声明中使用synchronize关键字,意味着将对象本身用作锁。所以,如果你有多个对象,你的块就会根据对象进行同步。
答案 1 :(得分:2)
我更愿意同步methodOne
和methodTwo
,因为可以从对象外部调用它们。它们也可以在不嵌入process
的情况下调用。因此,每个方法都应该以线程安全的方式实现。
希望有所帮助。
答案 2 :(得分:2)
您的简化代码无法轻易辨别问题的本质。例如,count
是静态的,因此在实例级别锁定不起作用,但这可能只是一个干扰器。
更重要的考虑因素是methodOne
和methodTwo
两个公共方法,它们显然需要同步,但不能单独执行。如果您选择仅同步process
方法,则意味着您要求methodOne
和methodTwo
的所有其他呼叫者也要正确处理同步,这看起来非常不稳定设计。
此外,如果您不需要整个process
是原子的,并且它可以分解为两个单独的原子步骤,那么再次锁定遵循这些语义更自然。这取决于您是否要从程序中的其他位置调用methodOne
和methodTwo
。
答案 3 :(得分:1)
建议尽可能少地同步代码,因为它会产生争用(其他线程在等待)。因此,方法1是优选的。
答案 4 :(得分:0)
无论您是单独同步process
还是任何方法,您仍然不会在method1和method2之间保持一致(即在这些调用之间不会更改变量count
)。原因是变量count
是静态的,所以它不是线程安全的,即使它是在synchronized
方法中使用的。
答案 5 :(得分:0)
正如Adem所说,静态计数&#39;字段需要静态锁定。然而,这里有更大的界面设计问题。 methodOne
和methodTwo
都是 public ,这意味着可以从任何其他类调用它们。如果要求它们在同步上下文中执行,那么建议它们都使用同步机制。
如果不是methodOne
和methodTwo
是公开的,我的偏好是在更高级别执行同步化(因为这稍微更有效和灵活),即在process
方法,然后对另外两个方法发表评论,这两个方法指定必须从同步上下文中调用它们。