问题描述
我试图了解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();
}
}
解决方法
将信号量创建为空。 启动两个线程。 每次Thread1加载数组索引时,都会发布一个信号量单元。 在线程2中,在处理索引之前等待循环中的信号量。
摆脱睡眠呼叫。
,好吧,首先,您在这里没有共享的数据结构,该数组属于Thread-1,就是这样。
第二个-信号量不适用于此用例。如果我理解正确,则您希望在元素生成后立即进行1对1处理。信号量可以像在您的代码中一样使用,但是您将依靠纯粹的运气,因为Thread-1总是会做他的事情,而Thread-2会在之后立即启动-不会在现实生活中发生。这只是程序的流程,不包括内存一致性错误。可以将其重写为对每个元素使用信号量,但是在我看来,这太混乱了。
信号灯基本上就像是现代COVID-19时代的商店-商店中一次只能容纳5个人。一个人走进时就像semaphore.acquire()
,一个人走进时-semaphore.release()
。如果某人想进入而商店中没有足够的空间,则他等待下一个人离开(semaphore.acquire()
等到semaphore.release()
)。
基本上,如果您确实很固执,则可以使用原子类(例如AtomicInteger),锁甚至信号灯来编写此程序,它似乎可以工作(并且在大多数情况下可以),但是会产生一些与错误相关的信息到Java内存模型(线程1编写和线程2看不到更改),除非您知道自己在做什么。我建议使用java.util.concurrent
中的某些结构-例如AtomicIntegerArray.