Java:将对象序列化为异步文件 [英] Java: Serialize object to file asynchronously

查看:69
本文介绍了Java:将对象序列化为异步文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作Minecraft副本,并且有一个 Map< Vector3i,Chunk> 名为 chunks ,所有已加载的块每帧都会运行此循环:

  for(Vector3i v :chunksToUnrender){
...
CompletableFuture.runAsync(()-> {
try {
chunks.get(v).toFile(new File(String.format ( res-server / regions /%s。%s。%s.mcr,vx,vy,vz)));
已同步(chunksStateGuard){
chunks.remove(v);
}
} catch(IOException e){
e.printStackTrace();
System.err.println(无法保存块 + Utils.format3i(v));
}
});
}

此处的目标是异步卸载块。 Chunk.toFile(File)的内容是:

  public void toFile(文件文件)抛出IOException {
FileOutputStream fos = new FileOutputStream(file);
fos.write(SerializationUtils.serialize(this));
fos.flush();
fos.close();
}

尽管使用了 CompletableFuture ,每当卸载块时,游戏都会序列化并卸载该块,因此会短暂击中帧率。有什么方法可以避免在后台任务执行时中断主线程?

解决方案

如前面的评论中所述,您可以



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

/ p>

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 =自动检测 dynamicConfig = true >

< ;!-默认情况下,Ehcache将缓存的文件存储在temp文件夹中。 ->
<!-< diskStore path = java.io.tmpdir /> ->

< ;!-要求Ehcache在此路径中存储缓存->
< diskStore path = c:\\temp\\ehcache />

<!-名为cache1的示例缓存并且在10分钟内的寿命超过


如果有10000个以上的元素,它将溢出到
磁盘高速缓存中,在此配置中,该高速缓存将转到系统上定义的
处的java.io.tmp。在标准Linux系统上,它将是/ 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;

/ **
*缓存功能的演示类
* @author Rahul R
*
* /
公共类ApplicationCacheDemo {

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

CompletableFuture< Void>未来= CompletableFuture.runAsync(()-> {
try(ApplicationCache< CachableObject> cache = cacheFactory.getApplicationCache()){
CachableObject cacheContent = new CachableObject( A sample content);
int身份= cache.put(cacheContent);

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

future.join();
}
}

/ **
*将缓存其对象的类。
* @author Rahul R
*
* /

类CachableObject实现Serializable {
private static final long serialVersionUID = 1L;

私有字符串数据= null;

public CachableObject(){
super();
}

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

public String getData(){
返回数据;
}

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

@Override
public int hashCode(){
final int prime = 31;
int结果= 1;
结果=素数*结果+((数据==空)?0:data.hashCode());
的返回结果;
}

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

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

/ **
*通过Enum
实现的单例工厂* @author Rahul R
*
* /

枚举ApplicationCacheFactory {
实例;

public ApplicationCache< CachableObject> getApplicationCache(){
返回新的ApplicationCache<>( ApplicationContentCache);
}
}

/ **
*简单的缓存外观
* @author Rahul R
*
* /

类ApplicationCache< E>实现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();
缓存= 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));
个返回身份;
}

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

元素元素= cache.get(identity);

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

返回结果;
}

@Override
public void close()引发异常{
cm.shutdown();
}
}


I am making a Minecraft clone, and I have a Map<Vector3i, Chunk> called chunks that stores all the loaded chunks. Every frame, this loop runs:

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));
        }
    });
}

The goal here is to asynchronously unload chunks. The content of Chunk.toFile(File) is:

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

However, despite using a CompletableFuture, whenever a chunk is unloaded the game takes a framerate hit for a brief time, as it serializes and unloads the chunk. Is there any way to avoid interrupting the main thread as the background task works?

解决方案

As discussed in the comments earlier, you could further enhance the implementation with a cache that optimizes the serialization process whilst offering faster reads.

Following is a sample code that demonstrates setup and usage of a Cache, using ehCache.

Maven Dependency (within pom.xml)

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

The ehCache Configuration (ehcache.xml)

Note - This file should be available within the classpath.

<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>

The Various Java Classes

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:将对象序列化为异步文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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