Re: [KSUG] Spring에서 ThreadPoolTaskExecutor 로 쓰레드 실행시 setCorePoolSize 만큼만 실행 됩니다..

1,032 views
Skip to first unread message

SangYong Lee

unread,
Aug 5, 2016, 12:39:49 AM8/5/16
to ks...@googlegroups.com
간단한 테스트 코드입니다.

도움이 될지 모르겠네요

import com.google.common.collect.Queues;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;

import java.util.Queue;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.IntStream;

import static org.slf4j.LoggerFactory.getLogger;

/**
* Created by Naver on 2016-08-04.
*/
public class JobManagerServiceTest {
final Logger logger = getLogger(getClass());
final ThreadGroup threadGroup = new ThreadGroup("jobs");
ExecutorService executorService = Executors.newSingleThreadScheduledExecutor(Executors.defaultThreadFactory());
ExecutorService jobs = Executors.newFixedThreadPool(4, r -> new Thread(threadGroup, r));
Queue<Runnable> tasks = Queues.newConcurrentLinkedQueue();
private Random random = new Random();

@Test
public void threadChecker() throws Exception {
while (true) {
logger.info("Current Active Count {}", threadGroup.activeCount());
executorService.submit(() ->
tasks.parallelStream().forEach(runnable -> {
Future<?> future = jobs.submit(tasks.poll());
try {
future.get(7, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
})
);
sleep("sleep", 1);
if ( threadGroup.activeCount() <= 0 ) break;
}
}

@Before
public void makeTask() {
IntStream.range(0, 100).forEach(x -> tasks.add(() -> sleep("gogo", randomInt(1, 10))));
}

private void sleep(String txt, int second) {
try {
logger.info("{} {}", txt, second);
TimeUnit.SECONDS.sleep(second);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private int randomInt(int min, int max) {
return random.nextInt((max - min) + 1) + min;
}
}



2016년 8월 2일 오후 6:44, Bum Su Kim <ntmas...@gmail.com>님이 작성:

요즘계속.. 질문만 남기네요.. 항상 많은 도움 받고 있어 감사합니다.

저도 빨리 실력을 키워 도움 되는 일원이 되고 싶네요 흑...


질문은 크게 3가지 입니다..

1. 쓰레드가 고정된 사이즈 만큼만 실행된다.

2. 타임아웃 설정시 타임아웃 조건이 지정 시간내 쓰레드 리턴이냐, 아니면 지정시간동안 내부에서 아무런 작업도 안하는 행 상태를 체크하는 것인가?

3. 쓰레드 타임아웃이 발생시 예외가 발생하는지? 그리고.. 2번의 질문에서 전자의 경우는 무한루프로 테스트 해보면 되지만 후자의 경우 어찌 하여야 하는지 입니다...



ThreadPoolTaskExecutor 로 쓰레드를 실행시키고 getActiveCount()로 모니터링 해보면

Active 쓰레드가 항상 4로 나옵니다.. 예상한 시나리오는 4개의 쓰래드를 러닝하고 5번째 쓰레드 부터 maxpoolsize만큼 새로 할당된 pool로 실행되어 총 엑티브가 4개 이상이 나올거라 예상했는데 계속 4개쓰레드만 엑티브 상태이네요..

그리고 수행중이던 쓰레드가 완료되면 5번째 run한 쓰레드가 수행되는데 이상하게 5,6,7,8번 쓰레드에 셋팅한 domain값이 마지막에 실행한 쓰레드의 도메인값으로 나옵니다.


가령 아래와 같은 도메인을 ListQueu에서 꺼내서 하나씩 쓰레드로 런 시키면 1,2,3,4가 수행되고 이후에 9번 결과만 5번이 나옵니다.... 쓰레드 큐에 쌓여있는 대기 스레드를 계속 덮는건지.. 답답하네요..

1  targetDomainQueue.add("http://www.naver.com");
2 targetDomainQueue.add("http://www.google.com");
3 targetDomainQueue.add("http://www.dhtmlx.com");
4 targetDomainQueue.add("http://www.daum.net");
5 targetDomainQueue.add("http://www.nate.com");
6 targetDomainQueue.add("http://phantomjs.org");
7 targetDomainQueue.add("http://lesscss.org/");
8 targetDomainQueue.add("http://emberjs.com/");
9 targetDomainQueue.add("https://modernizr.com/");


===결과===

Col End  >> URL : http://www.naver.com Contents Length : 85226
Col End  >> URL : http://www.google.com Contents Length : 52252
Col End  >> URL : http://www.dhtmlx.com Contents Length : 204363
Col End  >> URL : http://www.daum.net Contents Length : 180579
Col End  >> URL : https://modernizr.com/ Contents Length : 5111
Col End  >> URL : https://modernizr.com/ Contents Length : 5111
Col End  >> URL : https://modernizr.com/ Contents Length : 5111
Col End  >> URL : https://modernizr.com/ Contents Length : 5111
Col End  >> URL : https://modernizr.com/ Contents Length : 5111
ALL Thread Completed
================


추가적으로 Timeout에 관해서 하나만 더 여쭤보면 

아래와 같이 timeout을 설정하여 쓰레드를 실행 시킬경우 설정 시간동안 쓰레드가 종료 되지 않으면 타임 아웃인지 아니면.. 내부적으로 인터럽트나 다른 예외로 인해 아무런 작업없이 해당 시간 이상 머물고 있으면 타임 아웃이 되는건가요.. 

아무리 타임아웃 값을 짧게 줘도 아무런 이벤트가  발생하지 않아서요..


crawlerTaskExecutor.execute(crawlingTask, 10000);


1번의 경우라면 시간내에 작업을 맞춰야 하는 것이고 2번의 경우라면 시간내에 완료되지 않더라도 쓰레드가 실행중이면 괜찮다는 말이 되는데 전자 인지 후자인지.. 궁금합니다.. ..  

타임아웃 시에는 특별한 예외등이 발생하게 되나요..?

타임아웃 테스트는.. 무한루프로 테스트 해보면 될까요^^ 전자라면 가능할텐데 후자라면.. 안될거 같고.. 어렵네요..


아래와 같이 AppConfig에 TaskExecutor을 정의 하였습니다.


@Bean(name="crawlerTaskEcecutor")
public ThreadPoolTaskExecutor crawlerTaskEcecutor(){
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(4);
pool.setMaxPoolSize(8);
pool.setThreadNamePrefix("[CrawlerThread]");
pool.setQueueCapacity(32);
pool.initialize();
return pool;
}




CrawlingJobCtrolTask 클래스에서 crawlingTask 를 쓰레드로 실행 시키고 있습니다.



public class CrawlingJobControlTask{
    @Autowired
    @Qualifier("crawlerTaskEcecutor")
    private ThreadPoolTaskExecutor crawlerTaskExecutor;

    @Autowired
    private CrawlingTask crawlingTask;
    public void run() {
    while (true) {
 crawlingTask.setTargetDomain(domain);
 crawlerTaskExecutor.execute(crawlingTask, 10000);
}
    }
}




@Data
@Component
@Scope("prototype")

public class CrawlingTask implements Runnable {

@Autowired
private Crawler crawler;
private String  targetDomain   = null;
@Override
public void run() {
             crawler.start(targetDomain);
}
}










--
이 메일은 Google 그룹스 'Korea Spring User Group Q&A' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 ksug+unsubscribe@googlegroups.com에 이메일을 보내세요.
https://groups.google.com/group/ksug에서 이 그룹을 방문하세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/ksug/1c2a7615-3e10-40f3-9731-f7632ead2ca8%40googlegroups.com을(를) 방문하세요.
더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.

Reply all
Reply to author
Forward
0 new messages