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

时间:2015-12-05 11:38:52

标签: java multithreading synchronized

所以我参加了这场赛马比赛,当一匹马到达终点线时,我引用了一种到达方法。假设我有10个线程,每匹马一个,第一匹到达的马确实在调用'到达':

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

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

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

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

1 个答案:

答案 0 :(得分:1)

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

如果两个线程同时尝试添加,则可能会添加两个元素(按任意顺序),只添加一个元素,或者甚至两个元素都不添加。

Javadoc的相关引用是:

  

请注意,此实施未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。 (结构修改是添加或删除一个或多个元素的任何操作,或显式调整后备数组的大小;仅设置元素的值不是结构修改。)

2)这取决于操作系统如何安排线程。对于常规同步块,不保证“公平”(在到达顺序中执行),尽管某些类(Semaphore是一个)可以让您选择公平的执行顺序。

e.g。您可以使用信号量实现公平的执行顺序:

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);
  }
}