有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java数组元素在多个线程之间的可见性

创建数组:

Uses the thread provided on startup since we only create the array once.

public static final Player[] PLAYERS = new Player[10];

写入数组:

Uses several different threads from a pool so that players can load concurrently.

public static Player loadPlayer(int freeIndex) {
    //slow code that loads the player's saved data.
    return PLAYERS[freeIndex] = player;
}

从数组读取:

Uses a single thread to process players in order of their index.

public static void process() {
    for(Player player : PLAYERS)
        player.process();
}

问题:在方法loadPlayer执行后,玩家是否会立即在方法过程中可见?如果不是(我怀疑是这样),我应该采取什么方法来解决问题


共 (3) 个答案

  1. # 1 楼答案

    不,如果没有同步,在一个线程中设置的值可能无法用于另一个线程。您可以查看here以了解有关内存屏障的更多详细信息

    在这种情况下,可以使用^{}进行同步

    • 在初始化中,创建一个CountDownLatch

      public static final Player[] PLAYERS = new Player[10];
      public static CountDownLatch lacth = new CountDownLatch(10);
      
    • 加载新的Player后,调用countDown

      public static Player loadPlayer(int freeIndex) {
          //slow code that loads the player's saved data.
          PLAYERS[freeIndex] = player;
          latch.countDown();
          return player;
      }
      
    • 在进程线程中,只需等待。在加载所有Player之后 线程将由最后一个countDown线程调用:

      public static void process() {
          latch.await();
          for(Player player : PLAYERS)
              player.process();
      }
      
  2. # 2 楼答案

    你说得对,玩家可能不会立即出现

    可以使用^{}而不是标准数组,以确保对players的更改对其他线程可见

    documentation

    The memory effects for accesses and updates of atomics generally follow the rules for volatiles, as stated in The Java Language Specification (17.4 Memory Model):

    get has the memory effects of reading a volatile variable.

    set has the memory effects of writing (assigning) a volatile variable.

    lazySet has the memory effects of writing (assigning) a volatile variable except that it permits reorderings with subsequent (but not previous) memory actions that do not themselves impose reordering constraints with ordinary non-volatile writes. Among other usage contexts, lazySet may apply when nulling out, for the sake of garbage collection, a reference that is never accessed again.

    weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides no guarantees with respect to previous or subsequent reads and writes of any variables other than the target of the weakCompareAndSet. compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing volatile variables.

  3. # 3 楼答案

    当您使用不同的线程加载播放器时,请修改共享集合。当并发程序编写不正确时,错误往往会分为三类:原子性、可见性或顺序

    为了使代码线程安全,需要使用lock或其他非阻塞集合,如AtomicReferenceArray,以确保线程可见性和线程安全。另外,volatile变量不能确保原子性,但变量将确保可见性

    原子性涉及哪些动作和动作集具有不可分割的效果。这是程序员最熟悉的并发方面:它通常被认为是互斥的。可见性决定了一个线程的效果何时可以被另一个线程看到。排序决定了一个线程中的操作何时会相对于另一个线程出现无序