以下是什么可以理解?
我在SO上经历了this帖子,但仍然无法组装它。
代码1:
synchronized(this){
// some code
}
码2:
Object lock = new Object();
synchronized(lock){
// some code
}
任何教程,或一些解释同步的链接,就像他们向孩子解释一样?
答案 0 :(得分:6)
基本上,Java中的每个对象都有一个“锁定”。
当线程到达synchronized(某事)的调用时,它必须在继续之前获取某些内容的锁定。如果你想一次只允许一个线程来修改对象的状态,最明显的事情就是同步该对象的锁定。如果允许并行调用不同的方法,则需要使用不同的锁。
如果您编写synchronized(this)或简单地同步,则线程必须获取与当前对象关联的锁(调用哪种方法)。
请注意,自Java 5.0以来,并发包提供了适当的locks,可以使用它来代替同步。
答案 1 :(得分:3)
将代码放在synchronized
块中实际上意味着,“一旦此代码开始运行,其他需要使用此对象的代码就无法同时运行。”
因此,如果线程#2正在执行code2
块中的代码,那么当涉及synchronized(lock)
代码时,它必须有效地查看所有其他线程以确保没有其他人在运行目前“同步”代码与lock
对象。线程#1肯定同时运行某些代码,但它可能是完全不相关的代码。如果是这样,线程#2开始运行“some code
”的东西是安全的。
同时,如果线程#1到达synchronized(this)
块,它也必须暂停并查看是否有其他线程正在使用this
。如果this
与lock
是同一个对象,我们就会遇到问题。我们被告知只有一个线程可以同时使用该对象(在同步块中)。然而,线程#2已经在使用它了。线程#1只需等待......等待......等待......直到线程#2最终完成。然后我们就可以继续了。
最终结果是一次只能运行一个synchronized
块(当然,使用特定对象)。
答案 2 :(得分: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实例,则其中只有一个可以同时位于两个受保护的代码块中。
但是使用第二个习语,你可以灵活地说一个线程在第一个受保护块中是安全的,另一个在另一个线程中是安全的。请注意,如果锁是相同的(在同一个锁对象上同步),行为将是第一个。
还有其他差异。一些作家开始指出 synchronized(this)的问题 - 我会在SO上指出你的另一篇文章: Avoid synchronized(this) in Java?
我强烈建议您阅读它,以及它链接到的三个帖子。
答案 3 :(得分:2)
假设您有一个Account
对象,该对象有一个方法:
void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
if (accountBalance >= debitAmount) {
accountBalance -= debitAmount;
beneficiary.credit(debitAmount);
}
else {
throw new InsufficientFundsException();
}
}
现在假设您有一个余额为100欧元的帐户,并且您有两次尝试将其借记70欧元。如果两个借方同时发生,您可以获得竞争条件,如下所示:
我们可以通过同步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是开始获取并发和锁定信息的好地方。