ExecutorService를 사용하여 설명 할 수없는 동작을 관찰하고 있습니다. 메모리에 약 800 명의 프로필을로드하는 응용 프로그램이 있습니다. 아래를 고려하십시오명백하게 유휴 상태의 스레드가있는 Java - ExecutorService
ExecutorService es = Executors.newFixedThreadPool(8); // 8 cores machine
Runnable enricherService = new Runnable() {
@Override
public void run() {
doEnrichment(conn, tmpCachePerson);
}
};
// tmpCachePerson is a ConcurrentLinkedQueue<Person>
while (tmpCachePerson.isEmpty() == false) {
es.execute(enricherService);
}
es.shutdown();
try {
while (!es.awaitTermination(24L, TimeUnit.HOURS)) {
System.out.println("Waiting for termination");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
이 조각은 1 개의 스레드 풀에 비해 매우 느립니다. 나는 코드에 println을 두었고 모든 스레드가 너무 자주 (~ 4s), 모든 스레드가 멈추는 것을 볼 수 있으며 최대 16 초 동안 그곳에 앉아서 다시 배치를 시작할 수 있습니다. 완료하려면 50 초가 걸립니다. 그때 아래의 구현을 시도 :
Runnable enricher2Thread = new Runnable() {
@Override
public void run() {
while (tmpCachePerson.isEmpty() == false) {
doEnrichment(conn, tmpCachePerson);
}
}
};
Thread t = new Thread(enricher2Thread);
t.start();
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
반면에이 작품을 콘솔에 인쇄를 중단하지 않고, 3 초에 완료 결코, 매우 빠르고, 하나 개의 스레드를 사용합니다.
첫 번째 조각의 고정 풀을 캐시 된 풀로 바꾸면이 스레드는 800 개의 스레드를 생성 한 후 3 초 만에 완료됩니다. 고정 풀에 800 개의 스레드를 배치하면 속도가 같아집니다. 누구나 고정 된 풀이 너무 자주 멈추는 이유를 이해할 수 있으며, 왜 그것이 1 스레드보다 빠르지 않은지 이해합니다. 아래는 8 개의 스레드로 볼 수있는 내용입니다. thread-1을 보면, 5 초 동안 간단한 게터에서 일시 중지됩니다. 로그의 다른 부분에서는 전체 작업이 250ms 정도 걸립니다.
2016-11-15 15:54:04.212 - pool-1-thread-1 - Starting
2016-11-15 15:54:04.212 - pool-1-thread-1 - Starting executing SQL
2016-11-15 15:54:04.212 - pool-1-thread-1 - Done executing SQL in 0 ms
2016-11-15 15:54:04.212 - pool-1-thread-1 - Starting adding
2016-11-15 15:54:04.212 - pool-1-thread-1 - Starting Getting Val
2016-11-15 15:54:04.212 - pool-1-thread-1 - Done Getting Val in 0 ms
2016-11-15 15:54:04.212 - pool-1-thread-1 - Starting Getting Root
2016-11-15 15:54:04.212 - pool-1-thread-1 - Done Getting Root in 0 ms
2016-11-15 15:54:04.212 - pool-1-thread-1 - Starting Getting Path
2016-11-15 15:54:04.212 - pool-1-thread-1 - Done Getting Path in 0 ms
2016-11-15 15:54:04.212 - pool-1-thread-6 - Starting
2016-11-15 15:54:04.212 - pool-1-thread-8 - Starting <-------------- All threads stop
2016-11-15 15:54:09.533 - pool-1-thread-8 - Starting executing SQL
2016-11-15 15:54:09.533 - pool-1-thread-6 - Starting executing SQL
2016-11-15 15:54:09.533 - pool-1-thread-8 - Done executing SQL in 0 ms
2016-11-15 15:54:09.533 - pool-1-thread-1 - Starting Getting Full Path
2016-11-15 15:54:09.533 - pool-1-thread-6 - Done executing SQL in 5320 ms
2016-11-15 15:54:09.533 - pool-1-thread-8 - Starting adding
2016-11-15 15:54:09.533 - pool-1-thread-6 - Starting adding
2016-11-15 15:54:09.533 - pool-1-thread-8 - Starting Getting Val
2016-11-15 15:54:09.533 - pool-1-thread-6 - Starting Getting Val
2016-11-15 15:54:09.533 - pool-1-thread-8 - Done Getting Val in 0 ms
2016-11-15 15:54:09.533 - pool-1-thread-8 - Starting Getting Root
2016-11-15 15:54:09.533 - pool-1-thread-1 - Done Getting Full Path in 5320 ms
2016-11-15 15:54:09.533 - pool-1-thread-1 - Starting Adding Image
2016-11-15 15:54:09.533 - pool-1-thread-8 - Done Getting Root in 0 ms
2016-11-15 15:54:09.533 - pool-1-thread-1 - Done Adding Image in 0 ms
2016-11-15 15:54:09.533 - pool-1-thread-8 - Starting Getting Path
2016-11-15 15:54:09.533 - pool-1-thread-1 - Done adding in 5321 ms
2016-11-15 15:54:09.533 - pool-1-thread-1 - Starting setting
2016-11-15 15:54:09.533 - pool-1-thread-1 - Done setting in 0 ms
2016-11-15 15:54:09.533 - pool-1-thread-1 - Done in 5321 ms
이 코드를 어떻게 향상시킬 수 있고 왜 멈추는 지 알기 원하십니까? 이
편집을 도움이된다면 나는 doEnrichment()의 코드를 게시 할 수 있습니다
private void doEnrichment(Connection conn, ConcurrentLinkedQueue<Person> tmpCachePerson) {
Person person = tmpCachePerson.poll();
if (person != null) {
ImageCollection personImageCollection;
String query = "SELECT epi.value, i.path FROM Image i "
+ "INNER JOIN EntityImageRelationship eir ON eir.id_image = i.id "
+ "INNER JOIN EntityType et ON eir.id_entity_type = et.id "
+ "INNER JOIN EntityPrimaryImage epi ON epi.type_to_entity_uid = eir.type_to_entity_uid "
+ "WHERE et.id = ? AND eir.id_entity_id = ? ORDER BY i.id ASC";
String tagQuery = "SELECT id, value FROM Tag t INNER JOIN EntityTagRelationship etr ON etr.id_tag = t.id WHERE etr.id_entity = ? AND etr.id_entity_type = ?";
try (PreparedStatement stmnt = conn.prepareStatement(query);
PreparedStatement tagStmnt = conn.prepareStatement(tagQuery)) {
personImageCollection = getEntityImages(conn, stmnt, person.getId(), person.getMovieEntityType());
person.setImageCollection(personImageCollection);
person.getImageCollection().setPrimaryImageIcon();
Set<String> tags = getEntityTags(conn, tagStmnt, person.getId(), person.getMovieEntityType()).keySet();
person.setTags(tags);
personCache.add(person);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
와 노동자를 시작
더 나은 패턴은 노동자의 폴링을 넣어하는 것입니다 끝난? 그렇다면 선물을 사용하고 get (long timeout, TimeUnit unit)을 호출합니다. – joseph
예, 좋습니다. 코드가 제작에 들어갈 때까지이 작업을 수행합니다. – user292272