(cc'ing serviceability-dev)

Thanks Steve, looks like this crept as part of some refactoring work [1]. Looks like PlatformLoggingMXBean has the same issue. I've created the following bug to track it:

7068328: BufferPoolMXBean and PlatformLoggingMXBean getObjectName may return null

If no one take it in the next few days then I can take it and get it push to jdk8 (listing you are contributer). The test will need a bit of clean-up, re-formatting, and throwing an exception rather than calling System.exit for example.

-Alan

[1] http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/77dd50ba670b



-------- Original Message --------
Subject: java.nio.BufferPoolMXBean getObjectName() occasionally returns null
Date:   Mon, 18 Jul 2011 22:54:35 +0100
From:   Steve Poole <[email protected]>
To:     [email protected]



Hi all, a small fix to a race condition that occurs under extreme and probably unrepresentative loading...

sun.management.ManagementFactoryHelper provides the default implementation of java.nio.BufferPoolMXBean. The getObjectName() method uses a volatile field to store the object name. The name is filled in using a lazy sync method. Under high load a timing window is exposed in which the lazy sync succeeds but a caller still recieves null.

The failing code is question is in src/share/classes/sun/management/ManagementFactoryHelper.java

The diff and testcase are attached.

I don't know if the testcase is the right form - it creates a bunch of threads that drive the method to expose the problem and is fairly quick. I can show it happening on Ubuntu with JDK7 and with my local build of JDK8.

Cheers

Steve



/*
 * Copyright (c) %YEARS% 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.
 */

/*
 * Portions Copyright (c) %YEARS% IBM Corporation
 */

import java.lang.management.BufferPoolMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class BufferPoolMXBeanObjectNameStressTest {

	
	/**
	 * This test exercises the BufferPoolMXBean getObjectName() method to ensure
	 * it functions under load.
	 * The getObjectName() method uses lazy instantiation which could fail if
	 * accessed via multiple threads.
	 *  
	 * 
	 */
	public static void main(String[] args) throws Exception {
		
		final ThreadPoolExecutor pool = new ThreadPoolExecutor(10,100,10,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
		
		
		
		
		for(int i=0;i<10000;i++) {
			pool.execute(new Runnable() {

				@Override
				public void run() {
					List<BufferPoolMXBean> byteBufferPools = 
						ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
					
						
						for (BufferPoolMXBean bean: byteBufferPools) {
							
							// Name should not be blank or null
							if(bean.getObjectName()==null) {
								System.out.println("TEST FAILED: bean name is null");
								System.exit(-1);
							}
							if(bean.getObjectName().equals("")) {
								System.out.println("TEST FAILED: bean name is empty");
								System.exit(-1);
							}
							
						}
				
					
				}});
			
			
		}
		
		pool.awaitTermination(1,TimeUnit.SECONDS);
		System.out.println("TEST PASSED");
		
	}

	
}

diff --git a/src/share/classes/sun/management/ManagementFactoryHelper.java b/src/share/classes/sun/management/ManagementFactoryHelper.java
--- a/src/share/classes/sun/management/ManagementFactoryHelper.java
+++ b/src/share/classes/sun/management/ManagementFactoryHelper.java
@@ -233,6 +233,11 @@
                                 ",name=" + pool.getName());
                             objname = result;
                         }
+			else {
+			// handle potential race condition where result is read just 
+			// before objname set on other thread.
+			  result=objname; 
+			}
                     }
                 }
                 return result;

Reply via email to