Java线程 - 同步代码

时间:2013-04-07 08:36:13

标签: java multithreading

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

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

我有两个问题:

  • 为什么不能用非对象阻止非静态方法 '这个'?
  • 为什么必须指定已阻止的对象 同步代码?

我已经阅读了SCJP for Java 6的第九章,但我仍然不清楚这一点。

我意识到这可能是一个基本问题,但我是Threading的新手。

8 个答案:

答案 0 :(得分:2)

  

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

你可以:

public void foo() {
    synchronized (lock) {
        ...
    }
}
  

为什么必须指定阻止同步代码的对象?

因为这是语言设计者选择设计语言的方式。 synchronized在实例方法上使用时,隐含地使用this作为锁。 synchronized在块上使用时必须明确指定锁定。

答案 1 :(得分:2)

你可以。 代码

synchronized foo() {
    // some stuff
}

在逻辑上等于代码

foo() {
    synchronized(this) {
        // some stuff
    }
}

我说“逻辑”因为这两个例子产生不同的字节码。

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

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

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

答案 2 :(得分:0)

  1. 您可以锁定对象的任何实例,但通常是程序员 使用thislocker ...
  2. 因为它限制其他线程对该部分代码的访问 (代码处理单元),以确保整个部分运行 一致性,没有任何东西(即变量)会被另一个线程警告。
  3. 考虑:

    a = 1;
    a++;
    

    线程1到达第二行,你期望a = 2但是另一个线程执行第一行,而不是2,第一个线程有a = 1,第二个线程有a = 2。现在:

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

    现在第二个帖子将被阻止进入code blocksynchronized身体),直到第一个离开它(释放锁定)。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

final Object lock = new Object() 同步(锁定){...}

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

synchronized foo(){....}

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

答案 5 :(得分:0)

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

这种做法在Java Concurrency in Practice中得到了很好的解释。但请注意,只有在您具备线程的基本经验时,本书才有用。

要记住一些小块:

  • 不要过度使用同步
  • 仅在需要保护整个方法时才使用方法级别同步
  • 使用不同的锁来保护两个不相关的实体,这将增加并发的可能性。或者,为了读取或写入两个不相关的实体,线程将阻塞相同的锁。

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

答案 6 :(得分:0)

concurrency教程,Synchronized methods部分:

  

要使方法同步,只需将synchronized关键字添加到其声明:

public class SynchronizedCounter {
private int c = 0;

public synchronized void increment() {
    c++;
}

public synchronized void decrement() {
    c--;
}

public synchronized int value() {
    return c;
}
}
  

如果count是SynchronizedCounter的一个实例,那么使这些方法同步有两个影响:

     
      
  • 首先,两个同步方法的调用不可能在同一个对象上进行交错。当一个线程正在为一个对象执行一个synchronized方法时,所有其他线程都会调用相同对象的同步方法(暂停执行)直到第一个线程完成该对象。

    < / LI>   
  • 其次,当一个synchronized方法退出时,它会自动建立一个before-before关系,以及后续调用同一个方法的同一个对象。这可以保证对所有线程都可以看到对象状态的更改。

  •   

简单地说,这就是Java中的同步工作原理。

  

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

对于实例方法是真的,对于静态方法,它锁定在类对象上。

  

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

请注意:

 public synchronized void increment() {
  c++;
 }

在行为上等同于:

 public  void increment() {
  synchronized(this) {
     c++;
  }
 }

在此代码段中,您可以将this替换为您想要的任何对象。

  

为什么必须指定阻止同步代码的对象?

有些人,我们称之为关键,代码块只能按顺序运行,但在不受控制的并发环境中,它可能会并行运行。这就是存在同步机制的原因。

所以我们可以像这样划分代码:

  • 可以并行运行的代码(默认情况)
  • 必须同步的代码(必须以某种方式标记)

该标记是通过synchronized关键字和相应的锁定对象进行的。

如果您有两个不能一起运行的不同关键代码块,它们都将具有synchronized关键字,并且假设它们具有相同的锁定对象。

当第一个块正在执行时,锁定对象变为“锁定”。如果在此期间需要执行第二个块,则该代码块的第一个命令是:

synchronized(lock) {

但该锁定对象处于锁定状态,因为第一个块正在执行。第二个块的执行在该语句上停止,直到第一个块完成执行,并解锁锁定对象的状态。然后第二个块可以继续执行(并再次锁定锁定对象)。

该机制称为mutual exclusionlock是与Java编程语言无关的一般概念。

可以找到“锁定对象锁定”过程的详细信息here

答案 7 :(得分:0)

我认为你的两个问题实际上是一样的。假设你想要在多个线程之间同步一个对象a的方法,你需要一个可以与之交谈的公共基本系统或通道,这实际上是对象锁提供的,所以当你想要一个对象的方法在那里同步时不需要另一个对象锁来执行此操作,因为您访问的对象本身具有此锁定,这就是设计语言的方式和原因。

虽然同步一个块不是同一个东西,但是线程可以拥有除此对象本身之外的不同的通话基础,例如,您可以为同步块设置与同步对象锁定相同的对象,因此该类的所有对象都可以在那个区块同步!