我在java多线程中有一个用例,我需要知道是否需要同步这种情况下的列表数据结构。还尝试在没有同步的情况下实现这种情况。
用例:
我正在尝试收集一些我可能需要递增一些值的统计数据。为此,我预加载了一个包含8个元素的arraylist,并且全部初始化为0.当请求到达时,每个请求将根据请求中的数据递增(更新)任何一个元素(使用索引)。因此,统计数据将被收集在这个arraylist中。这是唯一可以访问此列表以按顺序写入其中的线程。在任何情况下,都不会对此列表中的元素进行并行写入。
我将有一个读者线程,可能会尝试从这个arraylist获取所有数据,例如每2分钟一次。将构造一个for循环到列表的大小并通过其索引获取元素。我甚至可以从列表中获取旧的数据。
问题:
我需要知道这个arraylist是否需要针对上述使用模式进行同步?
如果不需要同步,那么并行操作两个线程不应该抛出任何类型的异常,尽管在读者线程中获取少量陈旧数据是可以的。
如果它需要同步,那么对我来说这将是一个性能打击,因为这个列表仅用于收集统计数据,我不能通过同步重载它。对于这种情况没有同步的任何其他解决方案..?
答案 0 :(得分:1)
由于有两个线程可以访问ArrayList,因此需要同步。
同步不只是写入,也是关于读取,因此陈旧的值不是读者线程阅读。
根据@OldCurmudgeon的建议,您可以拥有AtomicLong值的ArrayList。 AtomicLong中的 incrementAndGet()方法使得原子递增,因此不会读取过时值。
提出问题
- 我需要知道这个arraylist是否需要与>>上面的使用模式同步?
醇>
需要为get和set同步ArrayList。
你可以用
List<AtomicLong> stats = new ArrayList<AtomicLong>();
stats = Collections.synchronizedList(List<T> list)
- 如果不需要同步,则并行运行两个线程&gt;&gt;不应该抛出任何类型的异常,尽管在&gt;&gt;读取器线程中获取少量陈旧数据是可以的。
醇>
非同步代码也可以。它可能抛出错误的唯一一次是当你尝试向ArrayList添加一个元素时,同时ReaderThread正在使用Iterator从ArrayList读取数据。
- 如果需要同步,那么对我来说这将是一次性能打击,因为&gt;&gt;此列表仅用于收集统计信息,我无法通过&gt;&gt;同步重载它。对于这种情况没有同步的任何其他解决方案..?
醇>
创建AtomicLong的同步列表。
使用&#34; get&#34;从列表中读取操作。
使用incrementAndGet()方法写入线程。
答案 1 :(得分:0)
如果只有一个“写入线程”,如您所述,则无需同步以保持数据的完整性。您已经声明,阅读陈旧数据是可以接受的,因此这不是问题。
剩下的是更新单个值是否是原子操作,这意味着您无法读取部分更新的值。你说你正在递增计数器,所以我认为这些是整数或整数,无论哪种方式,这些增量应该是原子的,所以你不应该要求同步。
重读你的问题,你只提到“元素”,我认为它是一个整数或一个整数。相反,如果它们是复杂数据 - 必须更新的多个值,例如,如果您计算的是尝试的事务以及成功和失败的事务 - 那么您可能希望同步这些值以确保它们全部“加起来”。 / p>
答案 2 :(得分:0)
我担心你会有一个非常重的列表,毕竟原子开销会强制同步n次。为什么不将列表更改为并发列表?
答案 3 :(得分:0)
如果您可以在没有ArrayList的情况下进行管理,那么您可以尝试使用大小为8的AtomicLongArray。
On construction, all elements will be initialized to 0.
To write you can invoke incrementAndGet(index)
To get a value from an index, you will do get (index)
这将为您提供Java atomics的数组和线程安全性能。无需外部同步。
答案 4 :(得分:-1)
正如@Jim指出的那样 - 在你的场景中,你不必担心,因为只有一位作家。
即使有多位作家,如果你使用Atomic...
作为你的价值观,你仍然不需要同步。
以下是使用AtomicInteger
的演示:
// Use AtomicInteger to ensure no stats are missed.
final AtomicInteger[] stats = new AtomicInteger[10];
final Random random = new Random();
volatile boolean stop = false;
public void test() throws InterruptedException {
// Start them all at zero.
Arrays.setAll(stats, i -> new AtomicInteger());
// Fire up some threads.
Thread writer = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
// Increment a random stat.
stats[random.nextInt(stats.length)].incrementAndGet();
// Give a little time.
sleep(10);
}
});
// Start my reader.
Thread reader = new Thread(() -> {
while (!stop) {
// Add up all of the values.
int total = Arrays.stream(stats)
.mapToInt(a -> a.get())
.sum();
System.out.println("Sum = " + total);
sleep(20);
}
});
reader.start();
// Start my writer.
writer.start();
// Wait for the writer to finish.
writer.join();
// stop the reader.
stop = true;
reader.join();
}
private void sleep(int i) {
try {
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}