Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
线程安全的Java池,具有即时读取功能_Java_Multithreading_Thread Safety - Fatal编程技术网

线程安全的Java池,具有即时读取功能

线程安全的Java池,具有即时读取功能,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,要编写一个功能齐全的Java对象池,使用读/写锁不是什么大问题。 我看到的问题是,读取操作将不得不等到存储监视器(或类似的东西,取决于型号)被释放,这确实会减慢它的速度 因此,应满足以下要求: 读取(或获取)操作应该是即时的——使用某个键,应该立即返回对象的最新版本,而无需等待任何锁定 写入(创建/更新)-可能已排队,时间延迟合理,可能正在等待某个存储锁 有代码示例吗 我没有找到直接针对该问题的问题 它在一些讨论中突然出现,但我找不到一个问题完全涉及在Java中创建这样一个池的问题 当对数据结

要编写一个功能齐全的Java对象池,使用读/写锁不是什么大问题。 我看到的问题是,读取操作将不得不等到存储监视器(或类似的东西,取决于型号)被释放,这确实会减慢它的速度

因此,应满足以下要求:

  • 读取(或获取)操作应该是即时的——使用某个键,应该立即返回对象的最新版本,而无需等待任何锁定

  • 写入(创建/更新)-可能已排队,时间延迟合理,可能正在等待某个存储锁

  • 有代码示例吗


    我没有找到直接针对该问题的问题


    它在一些讨论中突然出现,但我找不到一个问题完全涉及在Java中创建这样一个池的问题

    当对数据结构的修改花费太长时间时(无论出于何种原因),简单地等待并写入锁定结构将不会成功。您无法预见何时有足够的时间在不阻止任何读取的情况下执行修改

    您唯一能做的(尝试做的)就是将写操作的时间减少到最小。正如@assylias所述,CopyOnWrite*通过在写操作时克隆数据结构来实现这一点,并在操作完成时自动激活修改后的结构

    这样,读取锁定将花费克隆操作的持续时间加上切换引用的时间。您可以将其扩展到数据结构的一小部分:如果只更改对象中的状态,则可以修改该对象的副本,然后将更复杂的数据结构中的引用更改为该副本

    另一种方法是在读取操作时或之前进行复制。通常,无论如何,您都会通过数据结构的API返回对象的副本,因此只需“缓存”该副本,在修改过程中,读卡器就可以访问缓存的副本。这就是数据库缓存aso所做的

    这取决于你的型号,什么最适合你。如果您对易于复制的数据进行的写操作很少,那么CopyOnWrite的性能可能会最好。如果要进行大量的写入,最好提供结构的单个“读取”/“缓存”状态,并不时切换

    AtomicReference<Some> datastructure = ...; 
    
    //copy on write
    
    synchronized /*one writer*/ void change(Object modification) 
    throws CloneNotSupportedException {
       Object copy = datastructure.clone();
       apply(copy, modification);
       datastructure.set(copy);  
    }
    
    Object search(Object select) {
       return datastructure.get().search(select);
    }
    
    // copy for read
    
    AtomicReference<Some> cached = new AtomicReference<Some>(datastructure.get().clone());
    
    synchronized void change(Object modification) {
        apply(datastructure, modification);
        cached.set(datastructure);
    }
    
    Object search(Object select) {
        return cached.get().search(select);
    }
    
    原子参考数据结构=。。。; //抄写 已同步/*一个写入程序*/void更改(对象修改) 抛出CloneNotSupportedException{ Object copy=datastructure.clone(); 申请(复印、修改); 数据结构集(副本); } 对象搜索(对象选择){ 返回datastructure.get().search(选择); } //抄读 AtomicReference cached=新的AtomicReference(datastructure.get().clone()); 同步的无效更改(对象修改){ 应用(数据结构、修改); cached.set(数据结构); } 对象搜索(对象选择){ 返回cached.get().search(选择); }
    对于这两种操作,读取时没有等待。。但此时它需要切换引用。

    在这种情况下,您可以简单地使用volatile变量,以避免在读卡器端锁定,并使用
    synchronized
    方法保持写操作的独占性<代码>易失性会给读取增加很少甚至没有开销,但写入速度会有点慢。根据预期的吞吐量和读/写比率,这可能是一个很好的解决方案

    class Cache {
        private volatile Map<K, V> cache; //Assuming map is the right data structure
    
        public V get(K key) {
            return cache.get(key);
        }
    
        //synchronized writes for exclusive access
        public synchronized void put(K key, V value) {
            Map<K, V> copy = new HashMap<> (cache);
            V value = copy.put(key, value);
            //volatile guarantees that this will be visible from the getter
            cache = copy;
            return value;
        }
    }
    
    类缓存{
    私有易失性映射缓存;//假设映射是正确的数据结构
    公共V get(K键){
    返回cache.get(key);
    }
    //用于独占访问的同步写入
    公共同步作废put(K键,V值){
    映射副本=新哈希映射(缓存);
    V值=复制.放置(键,值);
    //volatile保证这将从getter中可见
    缓存=复制;
    返回值;
    }
    }
    
    这是一个完全无锁的Java对象池解决方案。供参考


    使用什么?类似于CopyOnWriteArrayList的模式可能会有所帮助。写操作获取写锁,复制池,将新项添加到副本,最后将池引用更改为副本,以便读者可以访问新池。通过使池不稳定,您可能可以完全解除读取端的锁定。这正是我所认为的CopyOnWriteArrayList,唯一的问题是-引用重新分配是线程安全的操作吗?在使用
    原子引用时是这样的。