{"action":"created","issue":{"url":"https://api.github.com/repos/EsotericSoftware/kryo/issues/381","repository_url":"https://api.github.com/repos/EsotericSoftware/kryo","labels_url":"https://api.github.com/repos/EsotericSoftware/kryo/issues/381/labels{/name}","comments_url":"https://api.github.com/repos/EsotericSoftware/kryo/issues/381/comments","events_url":"https://api.github.com/repos/EsotericSoftware/kryo/issues/381/events","html_url":"https://github.com/EsotericSoftware/kryo/issues/381","id":129244477,"number":381,"title":"Each thread should have its own Kryo, Input, and Output instances","user":{"login":"sirolf2009","id":3534736,"avatar_url":"https://avatars.githubusercontent.com/u/3534736?v=3","gravatar_id":"","url":"https://api.github.com/users/sirolf2009","html_url":"https://github.com/sirolf2009","followers_url":"https://api.github.com/users/sirolf2009/followers","following_url":"https://api.github.com/users/sirolf2009/following{/other_user}","gists_url":"https://api.github.com/users/sirolf2009/gists{/gist_id}","starred_url":"https://api.github.com/users/sirolf2009/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sirolf2009/subscriptions","organizations_url":"https://api.github.com/users/sirolf2009/orgs","repos_url":"https://api.github.com/users/sirolf2009/repos","events_url":"https://api.github.com/users/sirolf2009/events{/privacy}","received_events_url":"https://api.github.com/users/sirolf2009/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2016-01-27T19:29:54Z","updated_at":"2016-02-09T14:01:55Z","closed_at":"2016-02-09T13:56:26Z","body":"**Each thread should have its own Kryo, Input, and Output instances**\r\n\r\nWith this in mind I created the following class (I'm building a database backed by kryo):\r\n```java\r\npackage com.sirolf2009.database;\r\n\r\nimport java.util.Arrays;\r\nimport java.util.LinkedList;\r\nimport java.util.Set;\r\nimport java.util.concurrent.ArrayBlockingQueue;\r\nimport java.util.concurrent.BlockingQueue;\r\nimport java.util.function.Function;\r\nimport java.util.stream.Stream;\r\n\r\nimport org.reflections.Reflections;\r\n\r\nimport com.esotericsoftware.kryo.Kryo;\r\n\r\nimport lombok.AllArgsConstructor;\r\nimport lombok.Data;\r\n\r\npublic class Connection implements Runnable {\r\n\r\n\tprivate static Connection instance;\r\n\tprivate final Kryo kryo;\r\n\t@SuppressWarnings(\"rawtypes\")\r\n\tprivate LinkedList<MethodRequest> callbacks;\r\n\r\n\tprivate Connection(Database database) {\r\n\t\tkryo = new Kryo();\r\n\t\tgetRegisterable(database.getPackagePrefix()).forEach(clazz -> kryo.register(clazz));\r\n\t\tcallbacks = new LinkedList<>();\r\n\t}\r\n\r\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\r\n\t@Override\r\n\tpublic void run() {\r\n\t\twhile(true) {\r\n\t\t\tsynchronized(this) {\r\n\t\t\t\twhile(callbacks.isEmpty()) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tthis.wait();\r\n\t\t\t\t\t} catch (InterruptedException e) {\r\n\t\t\t\t\t\te.printStackTrace();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tfor(MethodRequest method : callbacks) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tmethod.result.add(method.function.apply(kryo));\r\n\t\t\t\t\t} catch(Exception e) {\r\n\t\t\t\t\t\te.printStackTrace();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tcallbacks.clear();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\r\n\tpublic <R> R execute(Function<Kryo, R> function) {\r\n\t\tBlockingQueue<R> queue = new ArrayBlockingQueue<R>(1);\r\n\t\tsynchronized(this) {\r\n\t\t\tcallbacks.add(new MethodRequest(queue, function));\r\n\t\t\tthis.notifyAll();\r\n\t\t}\r\n\t\ttry {\r\n\t\t\treturn queue.take();\r\n\t\t} catch (InterruptedException e) {\r\n\t\t\te.printStackTrace();\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\r\n\tpublic Stream<Class<?>> getRegisterable(String packagePrefix) {\r\n\t\tSet<Class<?>> entities = new Reflections(packagePrefix).getTypesAnnotatedWith(DBEntity.class);\r\n\t\treturn entities.stream().flatMap(entity -> getRegisterable(entity));\r\n\t}\r\n\r\n\tpublic Stream<Class<?>> getRegisterable(Class<?> clazz) {\r\n\t\tif(Object.class.isAssignableFrom(clazz)) {\r\n\t\t\treturn Arrays.stream(clazz.getDeclaredFields()).flatMap(field -> getRegisterable(field.getType()));\r\n\t\t}\r\n\t\treturn Stream.empty();\r\n\t}\r\n\r\n\tpublic static Connection getInstance(Database database) {\r\n\t\tif(instance == null) {\r\n\t\t\tinstance = new Connection(database);\r\n\t\t\tnew Thread(instance).start();\r\n\t\t}\r\n\t\treturn instance;\r\n\t}\r\n\r\n\t@Data\r\n\t@AllArgsConstructor\r\n\tprivate static class MethodRequest<R> {\r\n\r\n\t\tprivate BlockingQueue<Object> result;\r\n\t\tprivate Function<Kryo, R> function;\r\n\r\n\t}\r\n\r\n}\r\n```\r\nWhich is called as such:\r\n```java\r\npublic void create(Object object) {\r\n\t\tconnection.execute(kryo -> {\r\n\t\t\tOutput out = fileAllocation.getOutput(object);\r\n\t\t\tkryo.writeObject(out, object);\r\n\t\t\tout.close();\r\n\t\t\treturn true;\r\n\t\t});\r\n\t}\r\n\r\n\tpublic <T> T read(Object ID, Class<T> type) {\r\n\t\tif(exists(ID, type)) {\r\n\t\t\treturn connection.execute(kryo -> {\r\n\t\t\t\tInput input = fileAllocation.getInput(ID, type);\r\n\t\t\t\tT object = kryo.readObject(input, type);\r\n\t\t\t\tinput.close();\r\n\t\t\t\treturn object;\r\n\t\t\t});\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n```\r\nyet I get this stacktrace while reading an object\r\n```\r\ncom.esotericsoftware.kryo.KryoException: Buffer underflow.\r\n\tat com.esotericsoftware.kryo.io.Input.require(Input.java:199)\r\n\tat com.esotericsoftware.kryo.io.Input.readVarInt(Input.java:373)\r\n\tat com.esotericsoftware.kryo.Kryo.readReferenceOrNull(Kryo.java:823)\r\n\tat com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:684)\r\n\tat com.sirolf2009.database.Database.lambda$1(Database.java:53)\r\n\tat com.sirolf2009.database.Connection.run(Connection.java:45)\r\n\tat java.lang.Thread.run(Thread.java:745)\r\n```\r\n\r\nAs you can see, the Connection class is a singleton, input and outputs are created when they are needed and closed when no longer needed and the kryo instance is final and inside of a singleton and will therefore only be created once. Yet I still get this exception. What's up?"},"comment":{"url":"https://api.github.com/repos/EsotericSoftware/kryo/issues/comments/181875138","html_url":"https://github.com/EsotericSoftware/kryo/issues/381#issuecomment-181875138","issue_url":"https://api.github.com/repos/EsotericSoftware/kryo/issues/381","id":181875138,"user":{"login":"magro","id":64285,"avatar_url":"https://avatars.githubusercontent.com/u/64285?v=3","gravatar_id":"","url":"https://api.github.com/users/magro","html_url":"https://github.com/magro","followers_url":"https://api.github.com/users/magro/followers","following_url":"https://api.github.com/users/magro/following{/other_user}","gists_url":"https://api.github.com/users/magro/gists{/gist_id}","starred_url":"https://api.github.com/users/magro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/magro/subscriptions","organizations_url":"https://api.github.com/users/magro/orgs","repos_url":"https://api.github.com/users/magro/repos","events_url":"https://api.github.com/users/magro/events{/privacy}","received_events_url":"https://api.github.com/users/magro/received_events","type":"User","site_admin":false},"created_at":"2016-02-09T14:01:55Z","updated_at":"2016-02-09T14:01:55Z","body":"@sirolf2009 Great you figured it out! Btw, kryo provides also a [KryoPool](https://github.com/EsotericSoftware/kryo/blob/master/src/com/esotericsoftware/kryo/pool/KryoPool.java#L29), which reduces extra time for Kryo setup (which is fairly expensive). Alternatively you can use ThreadLocal to have a Kryo instance per thread."}}