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

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

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

以下是一个基本示例:

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();
    }
}
import java.util.concurrent.Semaphore;
导入java.util.Random;
公共班机{
静态信号量信号量=新信号量(2);
静态类Thread1扩展了线程{
私有整数[]随机数组=新整数[50];
公开募捐{
试一试{
随机rng=新随机();
semaphore.acquire();
试一试{
对于(int i=0;i<50;i++){
randArray[i]=rng.nextInt()%100;
System.out.println(“随机数”+i+:“+randArray[i]);
《睡眠》(2000年);
}
}最后{
semaphore.release();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
静态类Thread2扩展了线程{
公开募捐{
试一试{
semaphore.acquire();
试一试{
对于(int i=0;i<50;i++){
//使用Thread1中生成的数组计算某些内容
《睡眠》(2000年);
}
}最后{
semaphore.release();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
公共静态void main(字符串[]args){
Thread1 t1=新的Thread1();
t1.start();
螺纹2 t2=新螺纹2();
t2.start();
}
}

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

第二,信号量不适合这个用例。如果我理解正确,您希望在生成元素后立即逐个处理。信号量可以像在你的代码中一样使用,但你会依赖于纯粹的运气,线程1总是做他的事情,线程2马上启动——这在现实生活中是不会发生的。这就是程序的流程,把内存一致性错误放在一边。这可以重写为对每个元素使用信号量,但在我看来这太混乱了

信号灯基本上类似于现代新冠病毒时代的商店——商店里一次只能有5个人。当一个人走进来时就像是
semaphore.acquire()
,而当一个人走出去时就像是
semaphore.release()
。如果有人想进入,但商店里没有足够的空间,他会等待下一个人离开(
semaphore.acquire()
等到
semaphore.release()


基本上,您可以使用原子类(比如AtomicInteger)、锁甚至信号量(如果您真的很固执的话)编写这个程序,它看起来可以工作(在大多数情况下是可以的),但它会有与java内存模型相关的细微错误(线程1编写和线程2没有看到更改),除非你知道你在做什么。我建议使用
java.util.concurrent
中的一些结构,比如说,首先,这里没有共享的数据结构,数组属于Thread-1,就是这样

第二,信号量不适合这个用例。如果我理解正确,您希望在生成元素后立即逐个处理。信号量可以像在你的代码中一样使用,但你会依赖于纯粹的运气,线程1总是做他的事情,线程2马上启动——这在现实生活中是不会发生的。这就是程序的流程,把内存一致性错误放在一边。这可以重写为对每个元素使用信号量,但在我看来这太混乱了

信号灯基本上类似于现代新冠病毒时代的商店——商店里一次只能有5个人。当一个人走进来时就像是
semaphore.acquire()
,而当一个人走出去时就像是
semaphore.release()
。如果有人想进入,但商店里没有足够的空间,他会等待下一个人离开(
semaphore.acquire()
等到
semaphore.release()


基本上,您可以使用原子类(比如AtomicInteger)、锁甚至信号量(如果您真的很固执的话)编写这个程序,它看起来可以工作(在大多数情况下是可以的),但它会有与java内存模型相关的细微错误(线程1编写和线程2没有看到更改),除非你知道你在做什么。我建议使用
java.util.concurrent
-like

中的一些结构创建空信号量。 启动两个线程。 每次Thread1加载数组索引时,都会发布一个信号量单元。 在线程2中,在处理索引之前,在循环中等待semahore


摆脱睡眠呼叫。

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


摆脱休眠调用。

是否应该在
Main
中声明数组?关于“在数组中生成数字…而不更改数组”,这是没有意义的。您的程序将数字存储到a中