(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;