5

为什么Java中两个不同的线程不能同时执行两个同步块。

编辑

public class JavaApplication4 {

    public static void main(String[] args) {
        new JavaApplication4();
    }

    public JavaApplication4() {
        Thread t1 = new Thread() {

            @Override
            public void run() {
                if (Thread.currentThread().getName().equals("Thread-1")) {
                    test(Thread.currentThread().getName());
                } else {
                    test1(Thread.currentThread().getName());
                }
            }
        };
        Thread t2 = new Thread(t1);
        t2.start();
        t1.start();

    }

    public synchronized void test(String msg) {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
            }
            System.out.println(msg);
        }
    }

    public synchronized void test1(String msg) {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
            }
            System.out.println(msg + " from test1");
        }
    }
}
4

4 回答 4

11

你的说法是错误的。只要不竞争同一个锁,任意数量的同步块都可以并行执行。

但是如果你的问题是关于块竞争同一个锁,那么问“为什么会这样”是错误的,因为这是整个概念的目的。程序员需要一种互斥机制,他们通过synchronized.

最后,您可能会问“为什么我们需要相互排除并行执行的代码段”。答案是,有许多数据结构只有在以某种方式组织时才有意义,并且当线程更新结构时,它必须逐部分进行,因此结构处于“损坏”状态在它进行更新时。如果此时出现另一个线程并尝试读取结构,或者更糟糕的是,自行更新它,整个事情就会崩溃。

编辑

我看到了您的示例和评论,现在很明显困扰您的是:synchronized方法修饰符的语义。这意味着该方法将争夺this' 的监视器上的锁定。同一个对象的所有synchronized方法都会争夺同一个锁。

于 2012-08-10T11:46:50.527 回答
4

这就是同步的全部概念,如果你在一个对象(或一个类)上加锁,那么其他线程都不能访问任何同步块。

例子

Class A{

public void method1()
{
 synchronized(this)//Block 1 taking lock on Object
 {
  //do something
 }
}

public void method2()
{
 synchronized(this)//Block 2 taking lock on Object
 {
  //do something
 }
}
}

如果一个对象的一个​​线程进入任何同步块,同一对象的所有其他线程将不得不等待该线程从同步块中出来才能进入任何同步块。如果有 N 个这样的块,则 Object 的一个线程一次只能访问一个块。请注意我对同一对象的线程的强调。如果我们正在处理来自不同对象的线程,则该概念将不适用。

让我还补充一点,如果您锁定class,上述概念将扩展到该类的任何对象。因此,如果不是说synchronized(this),我会使用synchronized(A.class),代码将指示 JVM,不管线程属于哪个对象,让它等待其他线程完成同步块执行。

编辑:请理解,当您锁定(通过使用同步关键字)时,您不仅仅是锁定一个块。您正在锁定对象。这意味着你告诉 JVM “嘿,这个线程正在做一些可能会改变对象(或类)状态的关键工作,所以不要让任何其他线程做任何其他关键工作”。关键工作,这里指的是同步块中的所有代码,它们锁定特定的对象(或类),而不仅仅是一个同步块。

于 2012-08-10T11:53:42.320 回答
0

两个线程可以同时执行同步块,直到它们没有锁定同一个对象。

如果块在不同的对象上同步......它们可以同时执行。

synchronized(object1){
    ...
}

synchronized(object2){
    ...
}

编辑: Please reason the output for http://pastebin.com/tcJT009i

在您的示例中,当您调用同步方法时,锁定是在同一个对象上获取的。尝试创建两个对象并查看。

于 2012-08-10T11:48:23.090 回答
0

这不是绝对正确的。如果您正在处理不同对象上的锁,那么多个线程可以执行这些块。

   synchronized(obj1){
       //your code here
   }

   synchronized(obj2){
       //your code here
   }

在上述情况下,一个线程可以执行第一个,第二个可以执行第二个块,关键是线程正在使用不同的锁。

如果线程正在处理相同的,则您的陈述是正确的lock。如果一个线程已获取锁并执行,则每个对象仅与 java 中的一个锁相关联,然后其他线程必须等到第一个线程释放该lock.Lock 可以通过synchronized块或方法获取.

于 2012-08-10T11:54:35.700 回答