Java:异步将对象序列化到文件

标签 java performance asynchronous serialization completable-future

我正在制作 Minecraft 克隆,并且我有一个 Map<Vector3i, Chunk>chunks存储所有加载的 block 。每一帧,这个循环都会运行:

for(Vector3i v:chunksToUnrender){
    ...
    CompletableFuture.runAsync(() -> {
        try {
            chunks.get(v).toFile(new File(String.format("res-server/regions/%s.%s.%s.mcr", v.x, v.y, v.z)));
            synchronized (chunksStateGuard) {
                chunks.remove(v);
            }
        } catch(IOException e) {
            e.printStackTrace();
            System.err.println("Unable to save chunk " + Utils.format3i(v));
        }
    });
}

这里的目标是异步卸载 block 。 Chunk.toFile(File)的内容是:

public void toFile(File file) throws IOException {
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(SerializationUtils.serialize(this));
    fos.flush();
    fos.close();
}

但是,尽管使用 CompletableFuture ,每当卸载一个 block 时,游戏都会在序列化并卸载该 block 时短暂地降低帧率。有什么办法可以避免后台任务工作时中断主线程吗?

最佳答案

正如前面评论中所讨论的,您可以使用缓存进一步增强实现,优化序列化过程,同时提供更快的读取速度。

以下示例代码演示了使用 ehCache 来设置和使用缓存。

Maven 依赖项(在 pom.xml 内)

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.9.0</version>
</dependency>

ehCache 配置 (ehcache.xml)

注意 - 该文件应该在类路径中可用。

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
    monitoring="autodetect" dynamicConfig="true">

    <!-- By default, Ehcache stored the cached files in temp folder. -->
    <!-- <diskStore path="java.io.tmpdir" /> -->

    <!-- Ask Ehcache to store cache in this path -->
    <diskStore path="c:\\temp\\ehcache" />

    <!-- Sample cache named cache1
    This cache contains a maximum in memory of 10000 elements, and will expire
    an element if it is idle for more than 5 minutes and lives for more than
    10 minutes.

    If there are more than 10000 elements it will overflow to the
    disk cache, which in this configuration will go to wherever java.io.tmp is
    defined on your system. On a standard Linux system this will be /tmp" -->
    <cache name="ApplicationContentCache" 
        maxEntriesLocalHeap="10000"
        maxEntriesLocalDisk="1000" 
        eternal="false" 
        diskSpoolBufferSizeMB="20"
        timeToIdleSeconds="300" timeToLiveSeconds="600"
        memoryStoreEvictionPolicy="LFU" 
        transactionalMode="off">
        <persistence strategy="localTempSwap" />
    </cache>
</ehcache>

各种 Java 类

import java.io.Serializable;
import java.util.concurrent.CompletableFuture;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

/**
 * Demo class for the caching functionality
 * @author Rahul R
 *
 */
public class ApplicationCacheDemo {

    public static void main(String... args) {
        ApplicationCacheFactory cacheFactory = ApplicationCacheFactory.instance;

        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try (ApplicationCache<CachableObject> cache = cacheFactory.getApplicationCache()) {
                CachableObject cacheContent = new CachableObject("A sample content");
                int identity = cache.put(cacheContent);

                CachableObject readContent = cache.get(identity);
                System.out.println(readContent.getData());          
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        future.join();
    }
}

/**
 * The class whose objects would be cached.
 * @author Rahul R
 *
 */

class CachableObject implements Serializable {
    private static final long serialVersionUID = 1L;

    private String data = null;

    public CachableObject() {
        super();
    }

    public CachableObject(String data) {
        super();
        setData(data);
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((data == null) ? 0 : data.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        CachableObject other = (CachableObject) obj;
        if (data == null) {
            if (other.data != null)
                return false;
        } else if (!data.equals(other.data))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "CachableObject [" + getData() + "]";
    }
}

/**
 * A singleton factory implemented through Enum
 * @author Rahul R
 *
 */

enum ApplicationCacheFactory {
    instance;

    public ApplicationCache<CachableObject> getApplicationCache() {
        return new ApplicationCache<>("ApplicationContentCache");
    }
}

/**
 * A simplistic cache facade
 * @author Rahul R
 *
 */

class ApplicationCache<E> implements AutoCloseable {    
    private CacheManager cm = null;
    private String cacheName = null;
    private Cache cache = null;

    public ApplicationCache(String cacheName) {
        super();
        setCacheName(cacheName);
        initializeCache();
    }

    private void initializeCache() {
        cm = CacheManager.getInstance();
        cache = cm.getCache(getCacheName());
    }

    public String getCacheName() {
        return cacheName;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }

    public int put(E value) {
        int identity = value.hashCode();
        cache.put(new Element(identity, value));
        return identity;
    }

    @SuppressWarnings("unchecked")
    public E get(int identity) {
        E result = null;

        Element element = cache.get(identity);

        if (element != null) {
            result = (E) element.getObjectValue();
        }

        return result;
    }

    @Override
    public void close() throws Exception {
        cm.shutdown();
    }
}

关于Java:异步将对象序列化到文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55265977/

相关文章:

Java - Rational Team Concert - 同时加载多个流工作区

c++ - 增加 Stack Size 的缺点以及 Stack Commit 和 Reserve 之间的区别

html - 一个http请求可以调用多个css文件吗?

c# - 方法返回任务和异步任务之间的区别

javascript - 页面重定向后 JQuery POST 中止

java - 你能在struts-config.xml中使用正则表达式吗?

java - Controller (Web 请求/antMatcher)安全性与方法(服务)级安全性

java - 在Java中是空类型

performance - JMeter 与研磨机?

wpf - 异步 MVVM 命令