1. 서론
http://bugs.sun.com/view_bug.do?bug_id=6427854
http://bugs.sun.com/view_bug.do?bug_id=6527572
jdk5, jdk6에서 Chartset.forName() 또는 Selector.open() 호출시 random(rarely)하게 NullPointerException(NPE)가 발생되는 문제가 있었다. 이 이유는 Selector.open() 호출시 thread safe하지 않으면서 생긴 문제이다.
java.lang.NullPointerException at sun.nio.ch.Util.atBugLevel(Util.java:290) at sun.nio.ch.SelectorImpl.<init>(SelectorImpl.java:40) at sun.nio.ch.WindowsSelectorImpl.<init>(WindowsSelectorImpl.java:104) at sun.nio.ch.WindowsSelectorProvider.openSelector(WindowsSelectorProvider.java:26) at java.nio.channels.Selector.open(Selector.java:209)
오픈소스쪽은 어떻게 구현되어 있는지 살펴보고, 앞으로 만들 솔루션들을 미리 대비해본다.
2. Zookeeper 사례
이런 문제를 해결하기 위해서 Zookeeper에서는 다음과 같이 해결했다. 이미 열고 닫음으로서 미리 초기화를 시켜 thread safe로 인한 문제가 없도록 했다. tokyotyrant도 비슷하게 사용.
<NIOServerCnxnFactory.java>
static {
....
/**
* this is to avoid the jvm bug:
* NullPointerException in Selector.open()
* http://bugs.sun.com/view_bug.do?bug_id=6427854
*/
try {
Selector.open().close();
} catch(IOException ie) {
LOG.error("Selector failed to open", ie);
}
}
3. Tomcat 사례
Tomcat은 synchronized(Selector.class)를 사용해서 thread safe하도록 했다.
<NioSelectorPool.java >
protected Selector getSharedSelector() throws IOException { if (SHARED && SHARED_SELECTOR == null) { synchronized ( NioSelectorPool.class ) { if ( SHARED_SELECTOR == null ) { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 SHARED_SELECTOR = Selector.open(); } log.info("Using a shared selector for servlet write/read"); } } } return SHARED_SELECTOR; }
@SuppressWarnings("resource") // s is closed in put() public Selector get() throws IOException{ if ( SHARED ) { return getSharedSelector(); } if ( (!enabled) || active.incrementAndGet() >= maxSelectors ) { if ( enabled ) active.decrementAndGet(); return null; } Selector s = null; try { s = selectors.size()>0?selectors.poll():null; if (s == null) { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 s = Selector.open(); } } else spare.decrementAndGet(); }catch (NoSuchElementException x ) { try { synchronized (Selector.class) { // Selector.open() isn't thread safe // http://bugs.sun.com/view_bug.do?bug_id=6427854 // Affects 1.6.0_29, fixed in 1.7.0_01 s = Selector.open(); } } catch (IOException iox) { } } finally { if ( s == null ) active.decrementAndGet();//we were unable to find a selector } return s; }
3, terracotta
dso-common이란 패키지안에서 Selector.open() 에서 발생하는 NPE를 catch해서 계속 retry하도록 코딩되어 있다.
CoreNIOServices.java
private Selector createSelector() {
Selector selector1 = null;
final int tries = 3;
for (int i = 0; i < tries; i++) {
try {
selector1 = Selector.open();
return selector1;
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} catch (NullPointerException npe) {
if (i < tries && NIOWorkarounds.selectorOpenRace(npe)) {
System.err.println("Attempting to work around sun bug 6427854 (attempt " + (i + 1) + " of " + tries + ")");
try {
Thread.sleep(new Random().nextInt(20) + 5);
} catch (InterruptedException ie) {
//
}
continue;
}
throw npe;
}
}
return selector1;
}
<SelectorUtil.java>
static { 46 String key = "sun.nio.ch.bugLevel"; 47 try { 48 String buglevel = System.getProperty(key); 49 if (buglevel == null) { 50 System.setProperty(key, ""); 51 } 52 } catch (SecurityException e) { 53 if (logger.isDebugEnabled()) { 54 logger.debug("Unable to get/set System Property '" + key + '\'', e); 55 } 56 } 57 if (logger.isDebugEnabled()) { 58 logger.debug("Using select timeout of " + SELECT_TIMEOUT); 59 logger.debug("Epoll-bug workaround enabled = " + EPOLL_BUG_WORKAROUND); 60 } 61 }
'java core' 카테고리의 다른 글
List.subList(fromIndex, toIndex) 실수 (0) | 2014.10.31 |
---|---|
Access restriction: The type BASE64Decoder is not accessible due to restriction on required library 이슈. (0) | 2014.04.07 |
GC 로그 로테이션 (GC Log Rotation) (0) | 2013.07.02 |
java default max heap size 파악 및 오픈 소스에서의 heap memory 설정 (0) | 2013.04.22 |
Google Collection Package & Google Guava (0) | 2013.03.14 |