当几个线程试图调用同一个同步方法时会发生什么?

What happens when few threads trying to call the same synchronized method?

所以我得到了这场赛马,当一匹马到达终点线时,我调用了一个到达方法。假设我有 10 个线程,每匹马一个,第一匹马确实调用了 'arrive':

public class FinishingLine {
    List arrivals;
    public FinishingLine() {
        arrivals = new ArrayList<Horse>();
    }

    public synchronized void arrive(Horse hourse) {
        arrivals.add(hourse);
    }
}

Ofc 我将到达方法设置为同步,但我不完全理解如果不同步会发生什么,教授只是说这不安全。

另一件我想更好地理解的事情是如何决定第一个线程完成后哪个线程?在第一个线程完成 'arrive' 并且方法解锁后,下一个线程将 运行?

1) 未定义行为是什么,但您应该假设这不是您希望它以任何您可以依赖的方式做的事情。

如果两个线程同时尝试添加,您可能会添加两个元素(以任一顺序)、仅添加一个元素,甚至可能两者都不添加。

Javadoc 中的相关引述是:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.)

2) 这取决于 OS 如何安排线程。对于常规同步块,无法保证 "fairness"(按到达顺序执行),尽管有某些 类(Semaphore 是一个)可以让您选择公平的执行顺序。

例如您可以使用信号量实现公平的执行顺序:

public class FinishingLine {
    List arrivals;
    final Semaphore semaphore = new Semaphore(1, true);

    public FinishingLine() {
        arrivals = new ArrayList<Horse>();
    }

    public void arrive(Horse hourse) {
        semaphore.acquire();
        try {
          arrivals.add(hourse);
        } finally {
          semaphore.release();
        }
    }
}

但是,使用 fair blocking queue 来处理并发访问会更容易:

public class FinishingLine {
  final BlockingQueue queue = new ArrayBlockingQueue(NUM_HORSES, true);

  public void arrive(Horse hourse) {
    queue.add(hourse);
  }
}