Java线程-同步代码

Java线程-同步代码,java,multithreading,Java,Multithreading,为什么必须指定哪个对象锁定了同步的代码块 您不必指定哪个对象锁定了同步方法,因为它总是被“this”(我相信)锁定 我有两个问题: 为什么不能用对象以外的对象阻止非静态方法 “这个”? 为什么必须指定已阻止的对象 同步代码? 我已经阅读了Java6的SCJP的第九章,但我仍然不清楚这一点 我意识到这可能是一个基本的问题,但我对线程是新手 您可以锁定对象的任何实例,但程序员通常 使用此或储物柜 因为它限制了其他线程对该部分代码的访问 (代码处理单元)所以你要确保整个部分都在 一致性和其他线程不

为什么必须指定哪个对象锁定了同步的代码块

您不必指定哪个对象锁定了同步方法,因为它总是被“this”(我相信)锁定

我有两个问题:

  • 为什么不能用对象以外的对象阻止非静态方法 “这个”?
  • 为什么必须指定已阻止的对象 同步代码?
我已经阅读了Java6的SCJP的第九章,但我仍然不清楚这一点

我意识到这可能是一个基本的问题,但我对线程是新手

  • 您可以锁定对象的任何实例,但程序员通常 使用
    储物柜
  • 因为它限制了其他线程对该部分代码的访问 (代码处理单元)所以你要确保整个部分都在 一致性和其他线程不会发出任何警报(即变量)
  • 考虑:

    a = 1;
    a++;
    
    一个线程到达第二行,您希望
    a=2
    ,但另一个线程执行第一行,而不是2,第一个线程的
    a=1
    ,第二个线程的
    a=2
    。现在:

    synchronized (whatever)
    {
       a = 1;
       a++;
    }
    
    现在,第二个线程将被阻止进入
    代码块
    synchronized
    主体),直到第一个线程离开它(释放锁)

  • 您可以锁定对象的任何实例,但程序员通常 使用
    储物柜
  • 因为它限制了其他线程对该部分代码的访问 (代码处理单元)所以你要确保整个部分都在 一致性和其他线程不会发出任何警报(即变量)
  • 考虑:

    a = 1;
    a++;
    
    一个线程到达第二行,您希望
    a=2
    ,但另一个线程执行第一行,而不是2,第一个线程的
    a=1
    ,第二个线程的
    a=2
    。现在:

    synchronized (whatever)
    {
       a = 1;
       a++;
    }
    

    现在,第二个线程将被阻止进入
    代码块
    synchronized
    主体),直到第一个线程离开它(释放锁)。

    您可以指定需要的任何对象,该对象应在同步代码块上具有锁。实际上,您根本不应该使用
    synchronize(this)
    (或者可能要小心,请参见)。

    您可以指定要锁定同步代码块的任何对象。实际上,您根本不应该使用
    同步(this)
    (或者可能要小心,请参阅)

    为什么不能用“this”以外的对象阻止非静态方法

    你可以:

    public void foo() {
        synchronized (lock) {
            ...
        }
    }
    
    为什么必须指定阻止同步代码的对象

    因为这就是语言设计者选择设计语言的方式
    synchronized
    在实例方法上使用时,隐式使用
    作为锁<代码>同步
    在块上使用时必须明确指定锁

    为什么不能用“this”以外的对象阻止非静态方法

    你可以:

    public void foo() {
        synchronized (lock) {
            ...
        }
    }
    
    为什么必须指定阻止同步代码的对象

    因为这就是语言设计者选择设计语言的方式
    synchronized
    在实例方法上使用时,隐式使用
    作为锁<代码>同步
    在块上使用时必须明确指定锁。

    您可以。 代码

    synchronized foo() {
        // some stuff
    }
    
    逻辑上等于代码

    foo() {
        synchronized(this) {
            // some stuff
        }
    }
    
    我之所以说“逻辑上”,是因为这两个示例生成不同的字节码

    如果方法
    foo()
    是静态的,则完成类对象的同步

    但是,您可能希望创建多个同步块,这些块在不同对象上同步到一个类中,甚至同步到一个方法中。在这种情况下,您可以使用
    synchronized(lock)
    ,其中
    lock
    不是
    this

    foo() {
        synchronized(one) {}
        ///..........
        synchronized(two) {}
    }
    
    你可以。 代码

    synchronized foo() {
        // some stuff
    }
    
    逻辑上等于代码

    foo() {
        synchronized(this) {
            // some stuff
        }
    }
    
    我之所以说“逻辑上”,是因为这两个示例生成不同的字节码

    如果方法
    foo()
    是静态的,则完成类对象的同步

    但是,您可能希望创建多个同步块,这些块在不同对象上同步到一个类中,甚至同步到一个方法中。在这种情况下,您可以使用
    synchronized(lock)
    ,其中
    lock
    不是
    this

    foo() {
        synchronized(one) {}
        ///..........
        synchronized(two) {}
    }
    

    每个对象都有一个可以同步的锁:

    最终对象锁=新对象() 已同步(锁定){…}

    如果你想同步整个方法,你不能说是哪个对象,所以它总是“this”对象

    同步的foo(){…}


    顺便说一下,第一种锁定方式更好。

    每个对象都有一个可以同步的锁定:

    最终对象锁=新对象() 已同步(锁定){…}

    如果你想同步整个方法,你不能说是哪个对象,所以它总是“this”对象

    同步的foo(){…}


    顺便说一句,第一种锁定方式更好。

    不建议使用此锁定每个方法,因为它在大多数情况下会降低并发性。因此,建议使用锁剥离,其中只有需要保护的特定代码部分保留在同步块中

    这是一种在实践中得到很好解释的做法。但请注意,这本书只有在您有一些线程的基本经验时才有用

    要记住一些金块:

    • 不要过度使用同步
    • 仅当需要保护整个方法时才使用方法级同步
    • 使用不同的锁来保护两个不相关的实体,这将增加并发的机会。否则,对于读取或写入两个不相关的实体,线程将阻塞在同一个锁上

      public void incrementCounter1(){
           synchronized(lockForCounter1){
               counter1++;
           }
      }  
      
      public void incrementCounter2(){
           synchronized(lockForCounter2){
               counter2++;
           } 
      }
      

    不建议使用
    锁定每个方法,因为它会减少