JDK-7145454 : JVM wide monitor lock in Currency.getInstance(String)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 7
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2012-02-14
  • Updated: 2016-09-29
  • Resolved: 2012-03-27
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u80Fixed 8 b32Fixed
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_01"
Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
Java HotSpot(TM) 64-Bit Server VM (build 21.1-b02, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.18-274.3.1.e15 x86_64

EXTRA RELEVANT SYSTEM CONFIGURATION :
multi-threaded (~50 thead) process with high throughput

A DESCRIPTION OF THE PROBLEM :
When you call String.format("%s.%s", s1, s2), where s1 and s2 are any string, this ends up entering a synchronized block on a static object (instances) in java.util.Currency and can block all threads in the system doing the same thing.  This somewhat antisocial thread policy is not documented.



REGRESSION.  Last worked in version 6u29

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Just set up lots of threads doing a String.format() and watch it using jvisualvm on the Threads tab

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I do not expect String.format() to ever need to block, as there is no indication that there is any requirement for it to have any state.
ACTUAL -
JVM-wide monitor locks,severely limiting throughput.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package bnpp.xiphias.lvc;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class Locker {
	public static void main(String... args) {
		Locker locker = new Locker();
		locker.execute();
	}

	private void execute() {
		final ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
		
		executor.execute(new Runnable() {
			public void run() {
				while (true) {
					executor.submit(newTask());
				}
			}
		});
				
		try {
			Thread.sleep(120000);
		} catch(InterruptedException ie) {
			
		} finally {
			executor.shutdown();
		}
		
	}

	private Runnable newTask() {
		return new Runnable() {
			@Override
			public void run() {
				String.format("%s.%s", "a", "b");
			}
		};
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Do not use String.format(), which is not exactly an easy thing to achieve with a vast existing code-base

Comments
EVALUATION Remove synchronized block and use concurrent map for "instances" field.
19-03-2012