내 응용 프로그램에서 병 목을 가리키는 핀이 있는데, 내게는 Thread::setContextClassLoader으로 전화가 온다.setContextClassLoader가 동시에 호출 될 때 속도가 크게 느려짐
기본적으로 제 3 자 라이브러리와 관련된 문제로 인해 스레드의 컨텍스트 클래스 로더가 엉망입니다. 이유를 이해하려면 this question을 참조하십시오.
내 지식에 대한 공통의 하나였다 그리고이 같은 작동 집어 솔루션 : 그것은 단지 하나의 스레드가 실행되었을 때 setContextClassLoader에 대한 호출이 문제가 아니라는 것을 밝혀졌다
Thread thread = Thread.currentThread();
ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(newClassLoader);
try {
... // problematic code that uses the thread context class loader
} finally {
thread.setContextClassLoader(old);
}
을하지만, 둘 이상의 쓰레드가 그것을 할 때, 그것은 크게 느려집니다.
내가 문제를 분리하기 위해 다음과 같은 테스트 응용 프로그램을했습니다 :
ArrayList<Thread> threads = new ArrayList<Thread>();
int thread_count = 1;
long start = System.currentTimeMillis();
for (int i = 0; i < thread_count; i++) {
Thread thread = new Thread(new MyRunnable(100000000));
thread.start();
threads.add(thread);
}
for (Thread thread : threads) {
thread.join();
}
long total = System.currentTimeMillis() - start;
double seconds = (double)total/1000;
System.out.println("time in seconds: " + seconds);
을 그리고 이것은 MyRunnable 클래스 :
public class MyRunnable implements Runnable {
int _iterations;
public MyRunnable(int iterations) {
_iterations = iterations;
}
public void run() {
final Thread curr = Thread.currentThread();
final ClassLoader loader = ClassLoader.getSystemClassLoader();
for (int i = 0; i < _iterations; i++) {
curr.setContextClassLoader(loader);
}
}
}
는 기본적으로 스레드의 몇 가지를 열고, 현재의 스레드를 설정 컨텍스트 클래스 로더를 루프의 시스템 클래스 로더에 추가합니다.
내 컴퓨터에서 코드를 변경 한 후 업데이트 된 결과 : thread_count
이 1 일 때 0.5 초가 지나면 완료됩니다. 2 개의 스레드는 1.5 ~ 3 스레드 2.7 ~, 4 스레드는 4 ~ - 당신은 그림을 얻습니다.
스레드의 setContextClassLoader 구현을 살펴 보았습니다. 전달 된 클래스 로더에 멤버 변수가 설정되어있는 것으로 보입니다. 둘 이상의 스레드에서 실행할 때 그러한 오버 헤드를 설명하기 위해 잠금 (또는 공유 리소스에 대한 액세스)이 없음을 발견했습니다.
무엇이 여기에 있습니까?
P. 나는 JRE 1.5를 사용하고 있지만 1.6에서 똑같은 일이 일어난다.
편집 : @Tom Hawtin - 내가 언급 한 이유를 배제하기 위해 만든 코드 변경 사항을 확인하십시오. 시스템 클래스 로더를 한 번 가져 오더라도 스레드 수가> 1 일 때 결과가 더 느려집니다.
겨우 수백 사이클이지만 사용자 코드의 대부분은 단지 몇 사이클 일 뿐이므로 자신이보고있는 속도 저하를 쉽게 일으킬 수 있습니다. 또한 잠금은 병렬 처리를 효과적으로 배제합니다. 예, setContextClassLoader() 호출은 시간에 추가되지만 실제 응용 프로그램에서는 단 한 번의 루프에서 천만 번 호출하지 않습니다. 사용량은 앱의 총 사용량 중 미세한 부분 일 것입니다. 그것에 대해 걱정하지 마십시오. –
getSystemClassLoader를 호출하는 대신 빈 URLClassLoader를 작성하십시오. 동일한 결과가 표시됩니다. –
'ClassLoader system = ClassLoader.getSystemClassLoader();'를 루프 밖에서 (그리고 그것을 사용하여) 추가하면 대부분 문제가 해결됩니다. 또한 모든 경우의 성능이 크게 향상됩니다. –