您在 Java 中遇到的最常见的并发问题是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/461896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:55:03  来源:igfitidea点击:

What is the most frequent concurrency issue you've encountered in Java?

javamultithreadingconcurrency

提问by Alex Miller

This is a poll of sorts about common concurrency problems in Java. An example might be the classic deadlock or race condition or perhaps EDT threading bugs in Swing. I'm interested both in a breadth of possible issues but also in what issues are most common. So, please leave one specific answer of a Java concurrency bug per comment and vote up if you see one you've encountered.

这是关于 Java 中常见并发问题的各种调查。一个例子可能是经典的死锁或竞争条件,或者可能是 Swing 中的 EDT 线程错误。我对可能出现的问题的广度以及哪些问题最常见感兴趣。因此,请为每条评论留下一个 Java 并发错误的具体答案,如果您看到遇到的问题,请投票。

采纳答案by Kutzi

The most common concurrency problem I've seen, is not realizing that a field written by one thread is not guaranteedto be seen by a different thread. A common application of this:

我见过的最常见的并发问题是没有意识到一个线程编写的字段不能保证被不同的线程看到。这个的一个常见应用:

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}

As long as stop is not volatileor setStopand runare not synchronizedthis is not guaranteed to work. This mistake is especially devilish as in 99.999% it won't matter in practice as the reader thread will eventually see the change - but we don't know how soon he saw it.

只要停止不挥发setStoprun同步的,这是不能保证的工作。这个错误尤其严重,因为 99.999% 在实践中并不重要,因为读者线程最终会看到变化 - 但我们不知道他多久看到它。

回答by Alex Miller

One classic problem is changing the object you're synchronizing on while synchronizing on it:

一个经典问题是在同步对象时更改正在同步的对象:

synchronized(foo) {
  foo = ...
}

Other concurrent threads are then synchronizing on a different object and this block does not provide the mutual exclusion you expect.

其他并发线程然后在不同的对象上同步,并且此块不提供您期望的互斥。

回答by kohlerm

Use of a global object such as a static variable for locking.

使用全局对象(例如静态变量)进行锁定。

This leads to very bad performance because of contention.

由于争用,这会导致非常糟糕的性能。

回答by Dave Ray

My biggest problem has always been deadlocks, especially caused by listeners that are fired with a lock held. In these cases, it's really easy to get inverted locking between two threads. In my case, between a simulation running in one thread and a visualization of the simulation running in the UI thread.

我最大的问题一直是死锁,尤其是由持有锁触发的侦听器引起的。在这些情况下,很容易在两个线程之间获得反向锁定。在我的情况下,在一个线程中运行的模拟和在 UI 线程中运行的模拟的可视化之间。

EDIT: Moved second part to separate answer.

编辑:将第二部分移至单独的答案。

回答by Alex Miller

Unbalanced synchronization, particularly against Maps seems to be a fairly common problem. Many people believe that synchronizing on puts to a Map (not a ConcurrentMap, but say a HashMap) and not synchronizing on gets is sufficient. This however can lead to an infinite loop during re-hash.

不平衡的同步,尤其是针对 Maps 似乎是一个相当普遍的问题。许多人认为,将 puts 同步到 Map(不是 ConcurrentMap,而是 HashMap)而不同步 get 就足够了。然而,这可能会导致重新散列期间的无限循环。

The same problem (partial synchronization) can occur anywhere you have shared state with reads and writes however.

然而,同样的问题(部分同步)可能发生在任何你通过读写共享状态的地方。

回答by Brian Clapper

Honesly? Prior to the advent of java.util.concurrent, the most common problem I routinely ran into was what I call "thread-thrashing": Applications that use threads for concurrency, but spawn too many of them and end up thrashing.

老实说?在 出现之前java.util.concurrent,我经常遇到的最常见问题是我所说的“线程抖动”:使用线程进行并发的应用程序,但产生太多线程并最终导致抖动。

回答by Dave Ray

The dumbest mistake I frequently make is forgetting to synchronize before calling notify() or wait() on an object.

我经常犯的最愚蠢的错误是在对对象调用 notify() 或 wait() 之前忘记同步。

回答by Fabian Steeg

Though probably not exactly what you are asking for, the most frequent concurrency-related problem I've encountered (probably because it comes up in normal single-threaded code) is a

虽然可能不是你所要求的,但我遇到的最常见的与并发相关的问题(可能是因为它出现在普通的单线程代码中)是

java.util.ConcurrentModificationException

java.util.ConcurrentModificationException

caused by things like:

由以下原因引起:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }

回答by Brendan Cashman

Multiple objects that are lock protected but are commonly accessed in succession. We've run into a couple of cases where the locks are obtained by different code in different orders, resulting in deadlock.

多个受锁保护但通常连续访问的对象。我们遇到过几种情况,不同的代码以不同的顺序获取锁,从而导致死锁。

回答by Dave Ray

Not properly synchronizingon objects returned by Collections.synchronizedXXX(), especially during iteration or multiple operations:

未正确同步返回的对象Collections.synchronizedXXX(),尤其是在迭代或多个操作期间:

Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

...

if(!map.containsKey("foo"))
    map.put("foo", "bar");

That's wrong. Despite single operations being synchronized, state of map between invoking containsand putcan be changed by another thread. It should be:

那是错误的。尽管单操作是synchronized,调用地图之间的状态,contains并且put可以被另一个线程改变。它应该是:

synchronized(map) {
    if(!map.containsKey("foo"))
        map.put("foo", "bar");
}

Or with a ConcurrentMapimplementation:

或者使用ConcurrentMap实现:

map.putIfAbsent("foo", "bar");

回答by Alex Miller

A common problem is using classes like Calendar and SimpleDateFormat from multiple threads (often by caching them in a static variable) without synchronization. These classes are not thread-safe so multi-threaded access will ultimately cause strange problems with inconsistent state.

一个常见的问题是在没有同步的情况下使用来自多个线程的 Calendar 和 SimpleDateFormat 类(通常通过将它们缓存在静态变量中)。这些类不是线程安全的,因此多线程访问最终会导致状态不一致的奇怪问题。