如何让两个线程同时访问同步代码块?

4

在面试中,我被问到两个线程如何同时访问同步块的问题,但我无法想出可能发生这种情况的场景。两个线程是否可以同时访问同步块?


6
移除同步?如果您希望两个线程同时访问它,为什么要将其放在第一位? - Aniket Thakur
同步块(监视器)的目的是在任何时候只有一个线程拥有监视器。您能否解释一下您的情况? - Nitin Dandriyal
只是为了让其他回答更准确: “同步块”并不一定意味着线程的互斥。仅当线程锁定相同的监视器对象时才会发生互斥。例如,如果两个线程在不同的向量实例上运行Vector.add(..),则完全可以同时运行它们。 - Eyal Schneider
我知道这个,但最近在面试中遇到了这个问题。 - Meastro
@Schneider 感谢您的回复。您能举个例子来解释一下吗? - Meastro
显示剩余2条评论
5个回答

4
有同步块的原因是为了防止两个线程同时访问该块。当然,这仅适用于两个线程在相同对象上同步。例如,如果您执行以下操作:
synchronized (new Object()) {
// Multiple threads can execute here at the same time.
}

多个线程就可以在同一块中同时执行。


2
整个同步块的目的就是为了防止你所要求的情况发生,因此你需要删除同步块。

1
这是可能的,使用 信号量。请看下面的代码:
// Create a semaphore with 2 permitted threads
private static Semaphore semaphore = new Semaphore(2);

public static void main(String[] args) {
    // Create 10 threads which will call the critical section
    for (int i = 0; i < 10; i++) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    criticalSection();
                } catch (InterruptedException ignored) {
                }
            }
        };

        Thread t = new Thread(runnable);
        t.setName("Thread No. " + i);
        t.start();
    }
}

private static void criticalSection() throws InterruptedException {
    // Try to enter the critical section (synchronized block)
    semaphore.acquire();

    System.out.println("Some heavy job. Thread ID = " + Thread.currentThread().getName());
    Thread.sleep(3000);

    semaphore.release();
}

信号量只允许2个线程进入同步块。

0

两个线程不能同时访问同步块。

同步的主要目的是防止多个线程并发访问相同的方法/块。

来自Java文档同步

线程主要通过共享对字段和对象引用字段所引用的访问来通信。这种形式的通信非常高效,但可能会出现两种错误:线程干扰和内存一致性错误。防止这些错误所需的工具是同步。

synchronized(object){
  //block of statements to be synchronized
}

在这里,对象是指正在同步的对象的引用。

同步块确保在当前线程成功进入对象的监视器后才调用对象成员的方法。

一些相关链接

  1. javatpoint.com同步
  2. tutorialspoint.comjava_thread_synchronization

0

如果进入同步块的线程看到的是相同的锁,那么这是不可能的。

然而,如果问题涉及到一般的“同步块”,而没有提到获取的锁对象,则是允许的。例如:

public class MyStats {  
  private long total;
  private int count;

  public void add(long value) {
    synchronized(this) {
      this.total += value;
      this.count++;
    }
  }

  public static void main(String[] args) {
    final MyStats s1 = new MyStats();
    final MyStats s2 = new MyStats();

    Thread t1 = new Thread() {
      public void run() {
        s1.add(100);
      }
    };

    Thread t2 = new Thread() {
      public void run() {
        s2.add(200);
      }
    };
    ....
  }
}

在这个例子中,由于线程t1操作s1,线程t2操作s2,所以没有任何阻止线程在同一时间内进入同步块的东西。线程使用不同的锁。互斥是由锁实例确定的,而不是由同步块确定的,同步块只定义了一个作用域。

谢谢Schneider。这真的很有帮助。 - Meastro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接