Actually, there is another option available to us here.

The default implementation of userHomeImpl() is pretty cheap.  So we can simply remove the method and inline it all into userHome(), and avoid the userHome instance member altogether.  Threading problems go away.

In FS_Win32_Cygwin, we introduce a private static inner class with a static final field containing the user home:

  @Override
  public File userHome() {
    return UserHome.home;
  }

  private static class UserHome {
    static final File home = userHomeImpl();
  }

and let class initialization take care of the caching and memory synchronization for us.  Then we aren't paying the volatile read penalty on each access.

Though, I have to point out, a volatile read is far cheaper than constructing the PrivilegedAction needed to pass through the AccessController.doPrivileged to get the user.home system property.