private void doCreateOtherVm(final VM otherVM) {
    otherVM.invoke(new CacheSerializableRunnable("create root") {

      @Override
      public void run2() throws CacheException {
        getSystem();

        CacheListener<String, HomeBoy> listener = new CacheListenerAdapter<String, HomeBoy>() {
          @Override
          public void afterCreate(final EntryEvent event) {
            if (event.getCallbackArgument() != null) {
              lastCallback = event.getCallbackArgument();
            }
          }

          @Override
          public void afterUpdate(final EntryEvent event) {
            if (event.getCallbackArgument() != null) {
              lastCallback = event.getCallbackArgument();
            }
          }

          @Override
          public void afterInvalidate(final EntryEvent event) {
            if (event.getCallbackArgument() != null) {
              lastCallback = event.getCallbackArgument();
            }
          }

          @Override
          public void afterDestroy(final EntryEvent event) {
            if (event.getCallbackArgument() != null) {
              lastCallback = event.getCallbackArgument();
            }
          }
        };

        AttributesFactory<String, HomeBoy> factory = new AttributesFactory<>();
        factory.setScope(Scope.DISTRIBUTED_ACK);
        factory.setDataPolicy(DataPolicy.PRELOADED);
        factory.setCacheListener(listener);

        createRootRegion(REGION_NAME, factory.create());
      }
    });
  }
Make sure that value is only deserialized in cache whose application asks for the value.
geode-core/src/distributedTest/java/org/apache/geode/cache30/ValuesAreLazilyDeserializedRegressionTest.java