信号量问题:从并行线程访问线程变量

Semaphore Question: Accessing Thread Variable From A Parallel Thread

我想了解 Java 中的信号量,我想使用并行线程同时在数组中生成数字并使用该数据执行操作而不改变数组本身以避免竞争条件.在第一个线程中生成数字非常简单,如果程序连续工作,获取数据 post 生成也不会太难。但是,我不太明白如何在生成数组时从另一个线程访问数组。我知道信号量旨在用于控制对共享数据结构的访问,类似于互斥锁,我不清楚的是如何以合法的方式声明它(在本例中为数组)。

这是一个基本示例:

import java.util.concurrent.Semaphore;
import java.util.Random;

public class Main {
    static Semaphore semaphore = new Semaphore(2);

    static class Thread1 extends Thread {
        private int[] randArray = new int[50];

        public void run() {
            try {
                Random rng = new Random();
                semaphore.acquire();

                try {
                    for (int i = 0; i < 50; i++) {
                        randArray[i] = rng.nextInt() % 100;
                        System.out.println("Random number " + i + " : " + randArray[i]);

                        Thread.sleep(2000);
                    }
                } finally {
                    semaphore.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Thread2 extends Thread {

        public void run() {
            try {
                semaphore.acquire();
                try {
                    for (int i = 0; i < 50; i++) {
                        // calculate something using array generated in Thread1

                        Thread.sleep(2000);
                    }
                } finally {
                    semaphore.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Thread1 t1 = new Thread1();
        t1.start();
        Thread2 t2 = new Thread2();
        t2.start();
    }
}

首先,这里没有共享数据结构,数组属于 Thread-1,仅此而已。

其次 - 信号量不适合此用例。如果我理解正确的话,您希望在生成元素后立即进行 1 对 1 处理。信号量可以像在您的代码中一样使用,但是您将完全依靠运气,Thread-1 总是做他的事情而 Thread-2 紧随其后 - 在现实生活中不会发生。这只是程序的流程,不考虑内存一致性错误。这可以重写为对每个元素使用信号量,但在我看来这太乱了。

Semaphores 基本上就像现代 COVID-19 时代的商店——商店里一次只能有 5 个人。当一个人走进去时就像 semaphore.acquire(),当一个人走出去时 - semaphore.release()。如果有人想进入但商店里没有足够的 space - 他会等待下一个人离开(semaphore.acquire() 等到 semaphore.release())。

基本上,您可以使用原子 类(如 AtomicInteger)、锁甚至信号量来编写此程序,如果您真的很固执的话,它似乎可以工作(并且在大多数情况下可以),但是除非您知道自己在做什么,否则它会出现与 java 内存模型相关的细微错误(Thread-1 写入和 Thread-2 未看到更改)。我建议使用 java.util.concurrent 中的一些结构 - 比如 AtomicIntegerArray.

创建空信号量。 启动两个线程。 Thread1每次加载一个数组索引,post一个信号量单元。 在线程 2 中,在处理索引之前等待循环中的信号量。

摆脱睡眠电话。