8022640: ServiceRegistry (used by ImageIO) lack synchronization
authorjdv
Mon, 01 Feb 2016 15:39:02 +0530
changeset 35985 3005aefa003f
parent 35984 7f192a93c793
child 35986 dce986488bf2
8022640: ServiceRegistry (used by ImageIO) lack synchronization Reviewed-by: prr, psadhukhan
jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java
jdk/test/javax/imageio/spi/ServiceRegistrySyncTest.java
--- a/jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java	Fri Jan 29 15:21:55 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java	Mon Feb 01 15:39:02 2016 +0530
@@ -759,7 +759,7 @@
         this.category = category;
     }
 
-    public boolean registerServiceProvider(Object provider) {
+    public synchronized boolean registerServiceProvider(Object provider) {
         Object oprovider = map.get(provider.getClass());
         boolean present =  oprovider != null;
 
@@ -781,7 +781,7 @@
      *
      * @return true if the provider was previously registered.
      */
-    public boolean deregisterServiceProvider(Object provider) {
+    public synchronized boolean deregisterServiceProvider(Object provider) {
         Object oprovider = map.get(provider.getClass());
 
         if (provider == oprovider) {
@@ -797,22 +797,23 @@
         return false;
     }
 
-    public boolean contains(Object provider) {
+    public synchronized boolean contains(Object provider) {
         Object oprovider = map.get(provider.getClass());
         return oprovider == provider;
     }
 
-    public boolean setOrdering(Object firstProvider,
-                               Object secondProvider) {
+    public synchronized boolean setOrdering(Object firstProvider,
+                                            Object secondProvider) {
         return poset.setOrdering(firstProvider, secondProvider);
     }
 
-    public boolean unsetOrdering(Object firstProvider,
-                                 Object secondProvider) {
+    public synchronized boolean unsetOrdering(Object firstProvider,
+                                              Object secondProvider) {
         return poset.unsetOrdering(firstProvider, secondProvider);
     }
 
-    public Iterator<Object> getServiceProviders(boolean useOrdering) {
+    public synchronized Iterator<Object> getServiceProviders
+                                         (boolean useOrdering) {
         if (useOrdering) {
             return poset.iterator();
         } else {
@@ -821,11 +822,12 @@
     }
 
     @SuppressWarnings("unchecked")
-    public <T> T getServiceProviderByClass(Class<T> providerClass) {
+    public synchronized <T> T getServiceProviderByClass
+                              (Class<T> providerClass) {
         return (T)map.get(providerClass);
     }
 
-    public void clear() {
+    public synchronized void clear() {
         Iterator<Object> iter = map.values().iterator();
         while (iter.hasNext()) {
             Object provider = iter.next();
@@ -839,7 +841,7 @@
         poset.clear();
     }
 
-    public void finalize() {
+    public synchronized void finalize() {
         clear();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/spi/ServiceRegistrySyncTest.java	Mon Feb 01 15:39:02 2016 +0530
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     8022640
+ * @summary Test verifies whether ServiceProvider API's of
+ *          ServiceRegistry are safe for concurrent access.
+ * @run     main ServiceRegistrySyncTest
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Locale;
+import javax.imageio.spi.ImageInputStreamSpi;
+import javax.imageio.spi.ServiceRegistry;
+import javax.imageio.stream.ImageInputStream;
+
+public class ServiceRegistrySyncTest {
+    public static void main(String[] args) throws InterruptedException {
+
+        final ArrayList<Class<?>> services = new ArrayList<Class<?>>();
+        services.add(ImageInputStreamSpi.class);
+
+        final ServiceRegistry reg = new ServiceRegistry(services.iterator());
+
+        //create new thread for Registerer and Consumer Class
+        Thread registerer = new Thread(new Registerer(reg));
+        Thread consumer = new Thread(new Consumer(reg));
+
+        //run both registerer and consumer thread parallely
+        registerer.start();
+        consumer.start();
+    }
+
+    static class Consumer implements Runnable {
+        private final ServiceRegistry reg;
+        boolean go = true;
+        int duration;
+        long start, end;
+
+        public Consumer(ServiceRegistry r) {
+            reg = r;
+            //set 5000ms duration to run the test
+            duration = 5000;
+        }
+
+        @Override
+        public void run() {
+            start = System.currentTimeMillis();
+            end = start + duration;
+            while (start < end) {
+                //access the ServiceProvider API
+                reg.getServiceProviders(ImageInputStreamSpi.class, true);
+                start = System.currentTimeMillis();
+            }
+        }
+    }
+
+    static class Registerer implements Runnable {
+        private final ServiceRegistry reg;
+        boolean go = true;
+        int duration;
+        long start, end;
+
+        public Registerer(ServiceRegistry r) {
+            reg = r;
+            //set 5000ms duration to run the test
+            duration = 5000;
+        }
+
+        @Override
+        public void run() {
+            final int N = 20;
+
+            MyService[] services = new MyService[N];
+            for (int i = 0; i < N; i++) {
+                services[i] = new MyService();
+            }
+            start = System.currentTimeMillis();
+            end = start + duration;
+            while (start < end) {
+                //access the ServiceProvider API's
+                for (int i = 0; i < N; i++) {
+                    reg.registerServiceProvider(services[i]);
+                }
+                for (int i = 0; i < N; i++) {
+                    reg.deregisterServiceProvider(services[i]);
+                }
+                start = System.currentTimeMillis();
+            }
+        }
+    }
+}
+
+class MyService extends ImageInputStreamSpi {
+    public MyService() {
+    }
+
+    @Override
+    public String getDescription(Locale locale) {
+        return null;
+    }
+
+    @Override
+    public ImageInputStream createInputStreamInstance
+        (Object input, boolean useCache, File cacheDir) throws IOException {
+        return null;
+    }
+}