제가 이해한것을 바탕으로 질문드리겠습니다.
해당 코드에서 처음에 main스레드가 시작되면서 스레드가 0개이고 최대 5개인 스레드풀이 생성됩니다. 그 후 for문의 i=1이 시작되면서 첫번째 작업(Callable<Integer>구현객체)이 생성되고 작업큐에 들어갑니다.
여기서 thread-1이 생성되고 첫번째 작업을 실행합니다.
main스레드의 future.get()때문에 thread-1이 작업을 완료할 때까지 main스레드가 블록되기때문에 다음 for문의 i=2로 넘어가지를 못하고 thread-1의 첫번째 작업이 완료된 후 그 결과를 출력 한다음 다음 for문으로 넘어가는 방식.
그렇다면 여기서 사실상 스레드풀의 스레드가 최대 5개이지만 future.get()때문에 main스레드가 블록되서 다음 작업을 생성하고 작업큐에 넣지 못하기때문에 스레드드풀의 스레드가 더이상 생성되지 않고 스레드들이 작업들을 병렬적으로 처리할 수 없다. 즉 스레드 하나가 모든 작업을 다 순차적으로 처리한다.
저는 이렇게 이해했습니다. 그런데 막상 실행해보니까
이렇게 thread-1, thread-2, thread-3, thread-4, thread-5가 생성된 것을 알 수 있습니다. 분명 제일 처음에 thread-1이 생성되고 thread-1이 첫작업을 완료할 때까지 작업큐에 다른 작업이 들어올 수 없고 그렇다면 thread-2가 생성될 일이 없는 것 아닌가요?
챗지피티에 물어보니까 자꾸 작업을 병렬적으로 처리할 수 없다, 있다, 없다, 있다 무한반복해서 모니터 부술뻔했습니다.
왜 스레드가 5개나 생성된건가요??
장문의 질문 읽어주셔서 감사합니다.
1번스레드에서 결과값을 리턴해주는데 1번이 다시 받는게 안되어서 그럼
1번이 끝났으니 리턴받을 다음 스레드를 생성한것
답변 감사합니다!!!!
Any BlockingQueue may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing: - If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing. - If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread. - If a request cannot be queue
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
if (workerCountOf(c) < this.corePoolSize) { if (this.addWorker(command, true)) { return; } ...
어떤 BlockingQueue도 제출된 작업을 전송하고 보관하는 데 사용할 수 있습니다. 이 큐의 사용은 풀 크기 조정과 상호 작용합니다: - corePoolSize보다 적은 스레드가 실행 중인 경우, Executor는 큐에 추가하는 것보다 새로운 스레드를 추가하는 것을 선호합니다. - corePoolSize 이상의 스레드가 실행 중인 경우, Executor는 새로운 스레드를 추가하는 것보다 요청을 큐에 추가하는 것을 선호합니다. - 요청을 큐에 추가할 수 없는 경우, 새로운 스레드가 생성됩니다. 단, 이로 인해 maximumPoolSize를 초과하게 되면 작업이 거부됩니다.
그니까 코어수보다 적은 스레드가 실행중일때 작업이 들어오면 큐에 넣지 않고 스레드를 만들어 작업을 처리하기때문에 thread-1이 첫번째 작업을 끝내고 다음 작업 생성 및 처리 과정에서 thread-2를 만들어서 thread-2가 두번째 작업을 처리한다는 말씀이시죠? 그렇다면 결론적으로 thread는 5개가 만들어지지만 각 스레드의 작업이 끝나야만 다음 작업이 생성되므로 스레드 5개가 병렬적으로 작업 5개를 처리하는 것이 아닌 thread-1이 첫작업을 완료 후 thread-2가 두번째작업을 완료 후 thread-3이 세번째 작업을 완료 후... 이런식으로 진행되는거 맞을까요? 답변 감사합니다!!!!!
병렬이 안되는건 네가 task안에서 future.get() 호출해서 그런것뿐임
이해했습니다!! 감사합니다!!
질문 하나를 이해 못하겠는게 1~1, 1~6, 1~11이 아니라 왜 1~1, 1~2, 1~3 순차적으로 실행되냐는 말임?
작업이 완전히 종료된 후 다음 task를 넘기는데 왜 thread를 재사용하지 않고 새로 생성되냐를 물어보는것
아 내가 바보같이 이해했구나, 1번 스레드 작업 끝나면 바로 1번 스레드 재사용해야하는거 아님? 이말이구나
백갤러1이 최고다 엄청 빠르게 찾았네
백1님 말씀이 맞아요 감사합니다!!
나도 모르는 상태에서 답변한건데 답을 어떻게 찾았는지 과정을 알려줄게. 1. newFixedThreadPool 구현부로 이동 2. ThreadPoolExecutor 랑 LinkedBlockingQueue 객체가 사용된걸 확인. ThreadPoolExecutor 구현부로 이동 3. 이건 약간 기반지식 첨가인데, 뭔가를 "실행"하는건 보통 execute, run, start 이런 단어가 쓰임. 여기선 execute 임. execute 구현부로 이동
4. 이 경우는 운 좋게도 구현부 코드가 짧아서 파악이 쉬움. 조금만 읽어도 workerCountOf(c) < this.corePoolSize 조건부가 보임. (원하는 답) workerCountOf 는 이름대로 worker 수를 반환할거같아 근데 c 가 뭔지 모르겠음. gpt한테 질문함(gpt는 이럴때 쓰는거임). 스레드 수 관리하는 비트마스크래 (안중요함)
2에서 바로 ThreadPoolExecutor javadoc 열고 읽어도 원하는 답은 나올텐데 텍스트가 많아서 시간은 좀 걸렸을수도 있음
압도적 감사합니다!!! 구현부를 본다는게 api도큐먼트에서 검색해서 찾아본다는 말씀 맞죠??
intellij 에서 우클릭 -> 이동 -> 구현