2009-08-30 31 views
1

对以下内容有何理解?
我已经通过this后在SO,但仍然在亏损组装它。使用线程中的同步

代码1:

synchronized(this){ 
// some code 
} 

码2:

Object lock = new Object(); 

synchronized(lock){ 
// some code 
} 

任何教程,或者某些环节来解释同步像他们解释给孩子?

回答

3

在已经给出的其他优秀答案中没有提到的一件事是Code1和Code2之间的区别。在code1中,同步位于找到代码的对象的实例上,而在code2中,它位于对象内的特定锁对象上。

如果只有在外部类的两个同步块,还有的两者之间没有功能差异,但考虑到这一点:

 
class CodeOneClass { 
    ... 
    synchronized(this) { // or merely "synchronized" - it defaults to this 
     first protected code block 
    } 
    ... 
    synchronized(this) { 
     second protected code block 
    } 
... 
} 

class CodeTwoClass { 
    ... 
    Object lock1 = new Object(); 
    synchronized(lock1) { 
     first protected code block 
    } 
    ... 
    Object lock2 = new Object(); 
    synchronized(lock2) { 
     second protected code block 
    } 
... 
} 

如果两个线程试图使用CodeOneClass的同一个实例,其中只有一个可以同时在两个受保护的代码块中的任一个中。

但是有了第二个习惯用法,您可以灵活地说,一个线程处于第一个保护区,另一个处于另一个线程中是安全的。请注意,如果锁相同(在同一个锁对象上同步),则行为将作为第一个锁。

还有其他的区别。一些作家开始用同步(这)指出的问题 - 我想指出你另一篇文章在这里SO: Avoid synchronized(this) in Java?

我强烈建议你阅读它,和三个职位它链接到。

+0

其他答案也很好?希望我可以选择更多正确/有用的答案? – 2009-09-03 13:17:38

6

基本上,Java中的每个对象都有一个“锁”。

当一个线程到达一个调用synchronized(something)的地方时,它必须在继续之前获取某个东西的锁。如果你想一次只允许一个线程修改对象的状态,最明显的是同步该对象的锁定。如果允许不同的方法被并行调用,那么你需要不同的锁。

如果你写同步(this),或者只是同步,线程必须获取与当前对象(调用哪个方法)相关的锁。

请注意,自Java 5.0以来,并发包提供了可用于代替同步的正确locks

+0

您能否提供一些示例或链接以进一步理解该主题,谢谢! – 2009-08-30 15:25:56

+1

你读过这个吗? http://java.sun.com/docs/books/tutorial/essential/concurrency – Zed 2009-08-30 15:28:42

+0

我会,现在!谢谢! – 2009-08-30 15:31:48

3

将代码放在​​块中本质上意味着“一旦此代码开始运行,其他需要使用此对象的代码不能同时运行。”

所以,如果线程#2是你的code2块执行的代码,当涉及到synchronized(lock)代码它有效地环顾四周,在所有其他线程,以确保没有其他正在运行“同步”的代码与lock目前的对象。线程#1肯定同时运行一些的代码,但它可能是完全无关的代码。如果是这样,第二线程开始运行你的“some code”是安全的。同时,如果线程#1到达synchronized(this)块,它也必须暂停并查看是否有任何其他线程正在使用this。如果thislock是同一个对象,则说明存在问题。我们被告知只有一个线程可能同时使用该对象(在同步块中)。然而,线程#2已经在使用它。线程#1将不得不等待......并等待......并等待......直到最终线程#2完成。然后我们可以继续。

最终的结果是,一次只能运行一个​​块(当然有特定的对象)。

+0

很好解释! – 2009-08-30 15:39:06

2

假设你有一个Account对象,它有一个方法:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException 
{ 
    if (accountBalance >= debitAmount) { 
     accountBalance -= debitAmount; 
     beneficiary.credit(debitAmount); 
    } 
    else { 
     throw new InsufficientFundsException(); 
    } 
} 

现在,假设你有100欧元的余额帐户,你会得到两次尝试了70欧元借记它。如果两个借方发生在同一时间,你可以得到一个竞争条件这样的:

  • 首先借记支票账户余额:100> = 70,所以成功
  • 二借记支票账户余额:100 > = 70,所以成功
  • 第一次借记执行;账户余额变为30
  • 第二次借记执行;账户余额变为-40。 不应该被允许

我们可以通过对Account对象的锁同步预防事务的这种可怕的状态:

void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException 
{ 
    synchronized (this) { 
     if (accountBalance >= debitAmount) { 
     accountBalance -= debitAmount; 
     beneficiary.credit(debitAmount); 
     } 
     else { 
     throw new InsufficientFundsException(); 
     } 
    } 
} 

这可以确保在账户余额的测试和借记能不会因帐户余额的另一项测试而中断。

Sun Java tutorial是开始获取并发和锁定信息的好地方。