查询java多线程中的用例

时间:2017-01-04 15:27:35

标签: java multithreading

我在java多线程中有一个用例,我需要知道是否需要同步这种情况下的列表数据结构。还尝试在没有同步的情况下实现这种情况。

用例:

我正在尝试收集一些我可能需要递增一些值的统计数据。为此,我预加载了一个包含8个元素的arraylist,并且全部初始化为0.当请求到达时,每个请求将根据请求中的数据递增(更新)任何一个元素(使用索引)。因此,统计数据将被收集在这个arraylist中。这是唯一可以访问此列表以按顺序写入其中的线程。在任何情况下,都不会对此列表中的元素进行并行写入。

我将有一个读者线程,可能会尝试从这个arraylist获取所有数据,例如每2分钟一次。将构造一个for循环到列表的大小并通过其索引获取元素。我甚至可以从列表中获取旧的数据。

问题:

  1. 我需要知道这个arraylist是否需要针对上述使用模式进行同步?

  2. 如果不需要同步,那么并行操作两个线程不应该抛出任何类型的异常,尽管在读者线程中获取少量陈旧数据是可以的。

  3. 如果它需要同步,那么对我来说这将是一个性能打击,因为这个列表仅用于收集统计数据,我不能通过同步重载它。对于这种情况没有同步的任何其他解决方案..?

5 个答案:

答案 0 :(得分:1)

由于有两个线程可以访问ArrayList,因此需要同步。

同步不只是写入,也是关于读取,因此陈旧的值不是读者线程阅读。

根据@OldCurmudgeon的建议,您可以拥有AtomicLong值的ArrayList。 AtomicLong中的 incrementAndGet()方法使得原子递增,因此不会读取过时值。

提出问题

  
    
        
  1. 我需要知道这个arraylist是否需要与>>上面的使用模式同步?
  2.        

需要为get和set同步ArrayList。 你可以用
List<AtomicLong> stats = new ArrayList<AtomicLong>(); stats = Collections.synchronizedList(List<T> list)

  
    
        
  1. 如果不需要同步,则并行运行两个线程&gt;&gt;不应该抛出任何类型的异常,尽管在&gt;&gt;读取器线程中获取少量陈旧数据是可以的。
  2.        

非同步代码也可以。它可能抛出错误的唯一一次是当你尝试向ArrayList添加一个元素时,同时ReaderThread正在使用Iterator从ArrayList读取数据。

  
    
        
  1. 如果需要同步,那么对我来说这将是一次性能打击,因为&gt;&gt;此列表仅用于收集统计信息,我无法通过&gt;&gt;同步重载它。对于这种情况没有同步的任何其他解决方案..?
  2.        

创建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();
    }

}