我对Java中多线程的混淆。需要帮忙

时间:2010-02-14 09:22:43

标签: java multithreading

我对多线程存在疑问,在许多采访中我遇到了很多关于多线程的问题。

我说了很多关于获取对象的锁定。我怀疑的是,当你有两个同步的方法,并且有两个线程想要访问这两个方法时,ThreadA想要访问MethodA而ThreadB想要访问MethodB。

现在两个方法都在同一个对象中。但我习惯说获取一个对象的锁定,我没有听说获取锁定方法。现在两个线程可以并行访问MethodA和MethodB吗?我的假设是,一旦你获得了对象的锁定,没有其他线程可以处理它。不是吗?

同步的重要性是什么(XYZ.class)?

5 个答案:

答案 0 :(得分:7)

不,他们不能。如果我理解正确,那么你的意思是:

class Foo {

   public synchronized void methodA () {
      doSmth ();
   }

   public synchronized void methodB () {
      doSmthElse ();
   }

}

在这种情况下,synchronized修饰符等于:

class Foo {

   public void methodA () {
      synchronized (this) {
         doSmth ();
      }
   }

   public void methodB () {
      synchronized (this) {
         doSmthElse ();
      }
   }

}

这意味着每个Foo对象中只有一个线程可以在这两个方法中的一个内同时工作。

  

同步的重要性是什么(XYZ.class)?

这就是你在

的幕后所拥有的
class XYZ {
   public static synchronized void someMethod () { ... }
}

答案 1 :(得分:5)

将方法声明为synchronized与在“synchronized(this){...}”块中包含整个方法主体基本相同。因此,对同步方法的锁定在整个对象实例上,这意味着您将锁定其他想要在同一对象上使用同步方法的人。 如果您希望每个方法同步而不是每个对象同步,则必须通过在该特定方法中使用synchronized(guardObject)或使用java中的Lock对象之一来同步其他内容(其中大多数已添加在1.5)。

  

同步的重要性是什么(XYZ.class)?

这意味着您正在使用该类作为保护对象,这意味着类本身(而不是实例)中的锁将保护对该块的访问。使用对象实例作为保护的区别在于,如果您有一万个对象,那么您一次只能访问其中一个对象,而不是一次保护多个线程对一个实例的访问。

答案 2 :(得分:3)

如果methodA和methodB使用不同的数据结构,并且在其他人调用methodB时调用methodA是安全的,那么这两个方法应该使用不同的锁

这是同步(XYZ.class)

上的瘦

synchronized(XYZ.class)是你如何实现上述模式的 - 它是一个同步块:

  • 获取对象的锁(在此类中表示XYZ的java.lang.class实例)
  • 做了一些工作
  • 释放锁。

关键是要记住Java中的每个对象都有一个锁(技术术语是 monitor ),一次只能由一个线程保存。您可以为您有引用的任何对象请求锁定。

方法上的synchronized关键字:

public synchronized void foo() {
    //do something
}

只是语法糖:

public void foo() {
    synchronized(this) {
        //do something
    }
}

这种方法有一个明显的缺点:因为任何引用某个对象的人都可以获得它的锁定,如果外部调用者获取并保持对象锁定,同步方法将无法正常工作。

(顺便说一句,这就是为什么锁定XYZ.class也是一个坏主意:它是一个全局可访问的对象,你永远不知道谁可能决定获取它的锁定)

为了避免这些缺点,通常使用此模式而不是同步方法:

private final Object LOCK = new Object();
public void foo() {
    synchronized(LOCK) {
        //do something
    }
}

由于没有外部调用者可以引用LOCK对象,因此只有此类可以获取其锁定,并且synchronized方法将始终按预期工作。

当你有两个不同的方法需要单独锁定时,通常的方法是每个方法锁定一个不同的私有对象:

private final Object LOCKA = new Object();
private final Object LOCKB = new Object();
public void foo() {
    synchronized(LOCKA) {
        //do something
    }
}

public void bar() {
    synchronized(LOCKB) {
        //do something else
    }
}

然后一个线程可能调用foo()而另一个线程正在调用bar(),但是一次只能有一个线程调用foo(),并且只有一个线程可以调用bar( )一次。

答案 3 :(得分:1)

使用synchronized(XYZ.class)非常严格。这意味着由XYZ.class保护的任何代码只能由一个线程同时执行。你应该意识到这一点,因为它可能导致严重的饥饿问题。

答案 4 :(得分:0)

在进入关键部分的入口处进入监视器的线程定义为“同步” 因此,您可以将每个方法(不是整个类)定义为同步,甚至是方法中的代码块。 http://java.sun.com/docs/books/tutorial/essential/concurrency/locksync.html