在线程中使用同步

发布于 2024-08-02 21:45:09 字数 364 浏览 8 评论 0原文

以下内容可以理解为什么?
我已经浏览了这篇帖子,但仍然无法组装它。

code1:

synchronized(this){ 
// some code
}

code2:

Object lock = new Object();

synchronized(lock){
// some code
}

有任何教程或一些链接来解释同步,就像他们向孩子解释一样?

What could be the understanding of the following?
I have gone through this post at SO but still at a loss to assemble it.

code1:

synchronized(this){ 
// some code
}

code2:

Object lock = new Object();

synchronized(lock){
// some code
}

Any tutorial, or some links to explain synchronized like they explain it to a child?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不语却知心 2024-08-09 21:45:09

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

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

如果您编写synchronized(this),或者只是synchronized,则线程必须获取与当前对象(调用其方法)关联的锁。

请注意,从 Java 5.0 开始,并发包提供了正确的 可以用来代替同步。

Basically there is a "lock" associated with every object in Java.

When a thread reaches a call to synchronized(something), it has to acquire the lock of something before continuing. If you want to allow only one thread at a time to modify the state of an object, the most obvious thing is to synchronize on the lock of that object. If different methods are allowed to be called in parallel, you need different locks for that.

If you write synchronized(this), or simply synchronized, the thread must acquire the lock associated with the current object (of which method is called).

Note that since Java 5.0 there concurrent package provides proper locks which can be used instead of synchronization.

时光倒影 2024-08-09 21:45:09

在已经给出的优秀答案中没有提到的一件事是 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 的文章:
我强烈建议阅读它,它链接的

三个帖子到。

One thing not mentioned in the otherwise excellent answers already given is that difference between code1 and code2. In code1, the synchronization is on the instance of the object in which the code is found, and in code2, it's on the specific lock object within the object.

If there's only the two synchronized blocks in the enclosing class, there's no functional difference between the two, but consider this:

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
  }
...
}

If two threads are trying to use the same instance of CodeOneClass, only one of them can be in either of the two protected code blocks at the same time.

But with the second idiom, you have the flexibility to say that it's safe for one thread to be in the first protected block, and another to be in the other. Note that if the locks were the same (both synchronizing on the same lock object), the behavior would be as the first.

There are other differences. Some writers are beginning to point out issues with synchronized(this) - I would point you to another post here on SO:
Avoid synchronized(this) in Java?

I highly recommend reading it, and the three posts it links to.

羁拥 2024-08-09 21:45:09

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

因此,如果线程 #2 正在执行 code2 块中的代码,那么当涉及到 synchronized(lock) 代码时,它必须有效地环顾所有其他线程以确保此时没有其他人正在使用 lock 对象运行“同步”代码。线程 #1 肯定同时运行一些代码,但它可能是完全不相关的代码。如果是这样,线程#2 就可以安全地开始运行“some code”内容。

同时,如果线程 #1 到达 synchronized(this) 块,它也必须暂停并查看是否有其他线程正在使用 this。如果 thislock 是同一个对象,我们就会遇到问题。我们被告知只有一个线程可以同时使用该对象(在同步块中)。然而线程 #2 已经在使用它了。线程#1 只需要等待...等待...等待...直到线程#2 最终完成。然后我们就可以继续了。

最终结果是一次只能运行一个同步块(当然是针对特定对象)。

Putting code within a synchronized block essentially means, "Once this code starts running, other code that needs to use this object cannot run at the same time."

So, if Thread #2 is executing code in your code2 block, when it comes to the synchronized(lock) code it has to effectively look around at all the other threads to make sure nobody else is running "synchronized" code with the lock object at the moment. Thread #1 is certainly running some code at the same time, but it might be completely unrelated code. If so, it's safe for Thread #2 to start running your "some code" stuff.

Meanwhile, if Thread #1 gets to the synchronized(this) block, it too has to pause and see if any other threads are using this. If this is the same object as lock, we have a problem. We were told that only one thread can possibly use that object (in a synchronized block) at the same time. Yet Thread #2 is already using it. Thread #1 will just have to wait... and wait... and wait... until eventually Thread #2 finishes. Then we can proceed.

The end result is that only one synchronized block can run at a time (with a particular object, of course).

嘿看小鸭子会跑 2024-08-09 21:45:09

假设您有一个 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 教程 是获取以下信息的好地方:并发和锁定。

Suppose you have an Account object which has a method:

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

Now suppose you have an account with a balance of 100 euros, and you get two attempts to debit it by 70 euros. If the two debits occur at the same time, you can get a race condition like this:

  • First debit checks account balance: 100 >= 70, so succeeds
  • Second debit checks account balance: 100 >= 70, so succeeds
  • First debit executes; account balance becomes 30
  • Second debit executes; account balance becomes -40. Shouldn't be allowed

We can prevent this dire state of affairs by synchronizing on the Account object's lock:

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

This makes sure that the test on the account balance and the debit can't be interrupted by another test on the account balance.

The Sun Java tutorial is a good place to start for information on concurrency and locking.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文