代码之家  ›  专栏  ›  技术社区  ›  Kevin Boyd

在线程中使用同步

  •  1
  • Kevin Boyd  · 技术社区  · 15 年前

    对以下内容有什么理解?
    我经历过 this 尽管如此,但仍不知如何组装它。

    代码1:

    synchronized(this){ 
    // some code
    }
    

    代码2:

    Object lock = new Object();
    
    synchronized(lock){
    // some code
    }
    

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

    4 回复  |  直到 15 年前
        1
  •  3
  •   Community Egal    7 年前

    在已经给出的其他优秀答案中没有提到的一件事是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实例,则只能在 两个受保护的代码块之一 同时。

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

    还有其他的区别。一些作家开始指出 已同步(此) -我会给你指出另一个帖子: Avoid synchronized(this) in Java?

    我强烈推荐阅读它,以及它链接到的三篇文章。

        2
  •  6
  •   Zed    15 年前

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

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

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

    注意,自从Java 5,并发包提供了适当的 locks 可以用来代替同步。

        3
  •  3
  •   VoteyDisciple    15 年前

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

    所以,如果线程2在 code2 布洛克,说到 synchronized(lock) 代码它必须有效地查看所有其他线程,以确保没有其他人使用 lock 目前反对。线程1肯定在运行 一些 同时编写代码,但可能是完全不相关的代码。如果是,线程2可以安全地开始运行 some code “东西。

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

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

        4
  •  2
  •   Simon Nickerson    15 年前

    假设你有一个 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。 不应该被允许

    我们可以通过同步 账户 对象的锁:

    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 是了解并发性和锁定信息的好地方。