Java并发 - 改进了一个读取副本集合 [英] Java concurrency - improving a copy-on-read collection

查看:88
本文介绍了Java并发 - 改进了一个读取副本集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个多线程应用程序,其中共享列表经常写,偶尔读取行为。



具体来说,许多线程都会将数据转储到列表中,



这类似于讨论结束这个问题



在此提供以下解决方案:

  class CopyOnReadList< T> {

私人最终名单< T> items = new ArrayList< T>();

public void add(T item){
synchronized(items){
//持有锁时添加项。
items.add(item);
}
}

public List< T> makeSnapshot(){
List< T> copy = new ArrayList< T>();
synchronized(items){
//持有锁时进行复制。
for(T t:items)copy.add(t);
}
return copy;然而,在这种情况下,((b))(


}
并且,因为我从我的问题中学到了这里),只有一个线程可以写



是否有一种方法允许高并发写入备份列表,只有在 makeSnapshot()调用?

解决方案

其他操作可以允许并发,它们可以更慢。

  private final Lock lock = new ReentrantLock 
私人列表< T> items = new ArrayList< T>();

public void add(T item){
lock.lock();
//平凡锁定时间。
try {
//按住锁定时添加项目。
items.add(item);
} finally {
lock.unlock();
}
}

public List< T> makeSnapshot(){
List< T> copy = new ArrayList< T>(),ret;
lock.lock();
//平凡锁定时间。
try {
ret = items;
items = copy;
} finally {
lock.unlock();
}
return ret;
}

public static void main(string ... args){
long start = System.nanoTime();
Main< Integer> ints = new Main<>();
for(int j = 0; j <100 * 1000; j ++){
for(int i = 0; i <1000; i ++)
ints.add(i)
ints.makeSnapshot();
}
long time = System.nanoTime() - start;
System.out.printf(添加的平均时间为%,d ns%n,时间/ 100/1000/1000);
}

列印

 平均添加时间为28 ns 

每秒创建3000万条目,您将有一个线程平均访问列表。如果你每秒创建6000万个,你将有并发问题,但是你现在可能会有更多的资源问题。



使用Lock.lock )和Lock.unlock()可以更快,当有高争用率。但是,我怀疑你的线程将花费大部分时间来构建要创建的对象,而不是等待添加对象。


I have a multithreaded application, where a shared list has write-often, read-occasionally behaviour.

Specifically, many threads will dump data into the list, and then - later - another worker will grab a snapshot to persist to a datastore.

This is similar to the discussion over on this question.

There, the following solution is provided:

class CopyOnReadList<T> {

    private final List<T> items = new ArrayList<T>();

    public void add(T item) {
        synchronized (items) {
            // Add item while holding the lock.
            items.add(item);
        }
    }

    public List<T> makeSnapshot() {
        List<T> copy = new ArrayList<T>();
        synchronized (items) {
            // Make a copy while holding the lock.
            for (T t : items) copy.add(t);
        }
        return copy;
    }

}

However, in this scenario, (and, as I've learned from my question here), only one thread can write to the backing list at any given time.

Is there a way to allow high-concurrency writes to the backing list, which are locked only during the makeSnapshot() call?

解决方案

synchronized (~20 ns) is pretty fast and even though other operations can allow concurrency, they can be slower.

private final Lock lock = new ReentrantLock();
private List<T> items = new ArrayList<T>();

public void add(T item) {
    lock.lock();
    // trivial lock time.
    try {
        // Add item while holding the lock.
        items.add(item);
    } finally {
        lock.unlock();
    }
}

public List<T> makeSnapshot() {
    List<T> copy = new ArrayList<T>(), ret;
    lock.lock();
    // trivial lock time.
    try {
        ret = items;
        items = copy;
    } finally {
        lock.unlock();
    }
    return ret;
}

public static void main(String... args) {
    long start = System.nanoTime();
    Main<Integer> ints = new Main<>();
    for (int j = 0; j < 100 * 1000; j++) {
        for (int i = 0; i < 1000; i++)
            ints.add(i);
        ints.makeSnapshot();
    }
    long time = System.nanoTime() - start;
    System.out.printf("The average time to add was %,d ns%n", time / 100 / 1000 / 1000);
}

prints

The average time to add was 28 ns

This means if you are creating 30 million entries per second, you will have one thread accessing the list on average. If you are creating 60 million per second, you will have concurrency issues, however you are likely to be having many more resourcing issue at this point.

Using Lock.lock() and Lock.unlock() can be faster when there is a high contention ratio. However, I suspect your threads will be spending most of the time building the objects to be created rather than waiting to add the objects.

这篇关于Java并发 - 改进了一个读取副本集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆