RFR: 8273581: Change the mechanism by which JDK loads the platform-specific FontManager class [v3]
Brett Okken
github.com+2996845+bokken at openjdk.java.net
Mon Sep 20 17:02:13 UTC 2021
On Mon, 20 Sep 2021 11:27:32 GMT, Alexander Scherbatiy <alexsch at openjdk.org> wrote:
>> The SunFontManager constructor and its subclasses seem too big, and potentially throw some exceptions and this will ruin the holder idiom since all subsequent calls to this method will fail.
>
> I wrote a simple example which uses DLC and lazy initialization holder class idioms. The FontManager is only created when it is accessed the first time via the getInstance() method in both cases and they both fail if an exception is thrown during the class initialization.
>
> Is the problem with Holder idiom that it throws `ExceptionInInitializerError` which contains the original exception as the cause whereas with DLC the original exception is directly thrown?
>
> public class FontManagerFactory {
>
> private static volatile FontManager instance;
>
> public static FontManager getInstanceDLC() {
>
> FontManager result = instance;
> if (result == null) {
> synchronized (FontManagerFactory.class) {
> result = instance;
> if (result == null) {
> instance = result = new FontManager("One", "Two", "Three");
> }
> }
> }
> return result;
> }
>
> public static FontManager getInstanceHolder() {
> return FontManagerHolder.instance;
> }
>
>
> public static void main(String[] args) {
> String lazyInitializationIdiom = args[0];
> System.out.printf("Use lazy initialization idiom: %s%n", lazyInitializationIdiom);
> if ("DLC".equals(args[0])) {
> System.out.printf("DLC FontManager instance: %s%n", getInstanceDLC());
> } else if ("Holder".equals(args[0])) {
> System.out.printf("Lazy Initialization Holder FontManager instance: %s%n", getInstanceHolder());
> }
> }
>
> private static class FontManagerHolder {
> private static final FontManager instance = new FontManager("One", "Two", "Three");
> }
> }
>
> class FontManager {
> public FontManager(String... args) {
> System.out.println(args[5]);
> }
> }
> ```
> DLC:
>
> java FontManagerFactory DLC
> Use lazy initialization idiom: DLC
> Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
> at FontManager.<init>(FontManagerFactory.java:41)
> at FontManagerFactory.getInstanceDLC(FontManagerFactory.java:12)
> at FontManagerFactory.main(FontManagerFactory.java:28)
>
> Hodler:
>
> java FontManagerFactory Holder
> Use lazy initialization idiom: Holder
> Exception in thread "main" java.lang.ExceptionInInitializerError
> at FontManagerFactory.getInstanceHolder(FontManagerFactory.java:20)
> at FontManagerFactory.main(FontManagerFactory.java:30)
> Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
> at FontManager.<init>(FontManagerFactory.java:41)
> at FontManagerFactory$FontManagerHolder.<clinit>(FontManagerFactory.java:35)
> ... 2 more
Does that stack trace difference really matter?
if so, you could wrap the `return FontManagerHolder.instance;` in a try/catch that throws that caused by:
try {
return FontManagerHolder.instance;
} catch (java.lang.ExceptionInInitializerError e) {
final Throwable cause = e.getCause();
if (cause instanceof RuntimeException re) {
throw re;
}
//could wrap in IllegalStateException or just throw the error
}
If this getInstance method is called with any frequency, getting rid of the volatile access each time is a nice bonus.
-------------
PR: https://git.openjdk.java.net/jdk/pull/5517
More information about the client-libs-dev
mailing list