diff --git a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java index 8e747d2c0..d46f1a0ea 100644 --- a/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java +++ b/microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/CloudBlobContainerTests.java @@ -22,8 +22,14 @@ import java.net.URISyntaxException; import java.security.InvalidKeyException; import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.xml.parsers.SAXParser; import com.microsoft.azure.storage.*; +import com.microsoft.azure.storage.core.Utility; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -541,6 +547,49 @@ public void testCloudBlobContainerListBlobs() throws StorageException, IOExcepti assertTrue(blobNames.size() == 0); } + @Test + @Category({DevFabricTests.class, DevStoreTests.class}) + public void testSAXParserConcurrency() throws Exception { + final int totalCount = 200000; + final int numThreads = 200; + final AtomicInteger currentCount = new AtomicInteger(0); + final AtomicInteger pending = new AtomicInteger(0); + final AtomicInteger failureCount = new AtomicInteger(0); + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numThreads); + + do { + final int count = currentCount.incrementAndGet(); + pending.incrementAndGet(); + executor.execute(new Runnable() { + @Override + public void run() { + pending.decrementAndGet(); + if (count > totalCount) { + return; + } + try { + SAXParser parser = Utility.getSAXParser(); + if (!parser.isNamespaceAware()) { + failureCount.incrementAndGet(); + } + assertEquals(true, parser.isNamespaceAware()); + } catch (Exception e) { + fail(e.toString()); + } + } + }); + + assertEquals(0, failureCount.get()); + + while (pending.get() > numThreads * 2) { + Thread.sleep(10); + } + } while (currentCount.get() < totalCount); + executor.shutdown(); + executor.awaitTermination(1, TimeUnit.MINUTES); + executor.shutdownNow(); + } + /** * List the blobs in a container with a prefix * diff --git a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java index c82db7f63..3c809f5ff 100644 --- a/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java +++ b/microsoft-azure-storage/src/com/microsoft/azure/storage/core/Utility.java @@ -129,9 +129,8 @@ protected DateFormat initialValue() { * Thread local for SAXParser. */ private static final ThreadLocal saxParserThreadLocal = new ThreadLocal() { - SAXParserFactory factory; @Override public SAXParser initialValue() { - factory = SAXParserFactory.newInstance(); + SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); try { return factory.newSAXParser();