묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
프린터 예제 main메서드 throw InterruptedException 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]섹션5의 프린터 예제 코드에서 교재에서는 main메서드에 throw InterruptedException을 지정했는데, 영상에서는 따로 지정을 하지 않아서요.혹시 교재 코드에는 예외 던지는 코드가 들어간 이유 가 있을까요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
데몬 스레드 예시 코드 실행 결과
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]데몬스레드를 true로 설정하여 작성한 코드 실행 결과가main: main() startmain: main() endThread-0: run() start이렇게 나왔는데,main함수가 종료되었는데 Thread-0이 실행되는 이유가 무엇인가요?"main: main() end" 이 문자열이 출력되었어도 자바 프로그램이 완전히 종료되는데는 시간이 조금 더 걸려서 그런건가요?
-
해결됨김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
오타 ? 이미지 순서 오류 제보 합니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용] 두번째 스케줄링 큐, CPU 코어 1,2 에서 스레드 B1이 B2 로 이미지가 바뀐거 같습니다.
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
스택 영역 == 스레드 수
"스택 영역 == 스레드 수" 로 생각하면 될까요??별도로 프로그램을 실행하는데 필요한 부가적인 무언가?들 때문에 추가적인 스레드가 필요한 것은 제외하고 현재 진행하는 예제들을 생각해 봤을 때main, ThreadA, ThreadB 이렇게 생성한다고 가정해보면 스택 영역이 3개 존재한다고 이해해도 될까요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
질문
안녕하세요 문제1번 관련 문의 사항이 있어 글 남깁니다.1번에 getCount는 synchroinized 하는 이유가 뭔가요?중간에 호출되는 부분이 없는 것 같고, t1.join() t2.join() 으로 마지막 출력할때도,,, synchroinized이게 안필요하다는 생각이 들어서요 제가 이해를 잘못한건지 문의드립니다.
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
생산자,소비자와 작업큐 질문 드립니다.
앞서 생성자, 소비자 강의에서 생산자가 데이터를 생성하면 다음과 같이 데이터를 넣었고queue.offer(data);소비자는 큐에서 생산자가 생산한 데이터를 꺼내어 소비하였습니다.queue.poll(); 이번 강의에서는 큐에 작업을 넣고, 빼서 처리합니다.생산자 소비자에서는 데이터를 넣고 빼고 이번 스레드풀 강의에서는 작업을 넣고 빼니 처음에는 작업을 넣고 빼는 큐와 생산자,소비자가 사용하는 큐가 별도로 있는 건가? 했는데 강의를 들어보니 별도로 있는건 아니고 같은 큐인것 같더라구요. 그런데 생산자,소비자에서는 어떤 작업의 결과인 데이터를 생산하여 큐에 넣고 꺼내어 소비한다는 것이 직관적이어서 이해가 잘되었는데요.이번 강의에서는 생산자가 '작업'을 큐에 넣고 빼서 소비자가 큐에서 작업을 빼는데 큐에 넣는 주체가 '데이터'에서 '작업'으로 바뀌어 설명하니 무엇을 생산하는 것이지? 하며 헷갈린다고나 할까요.생산자소비자 강의에서처럼 어떤 작업의 결과를 큐에 넣고 빼는 것이 아니라실제로는 작업 자체를 생산하여 큐에 넣는건가요? 그러니까 앞선 생산자와 소비자는 단순 이해를 위한 것이고 실제로는 Runnable 이라던지 Callable 같은 작업 객체 자체가 생산되어 큐에 들어가는 것인가요? 감사합니다
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
AtomicInteger.get()을 CAS 연산 후 반환값으로 사용하면 안 되는 이유 공유
AtomicInteger.get()을 CAS 연산 후 반환값으로 사용하면 안 되는 이유 🚨 핵심 문제: 원자성에 대해서 다시 생각해보기CAS 연산의 원자성은 compareAndSet() 호출 자체에만 적용됨CAS 성공 후 get() 호출은 완전히 별개의 연산두 연산 사이에 다른 스레드가 개입 가능멀티스레드 환경에서는 언제든지 다른 스레드가 개입 가능개발자는 OS가 중간에 어떤 스레드를 호출할지 알 수 없음 🔍 문제 발생 메커니즘1. 시간적 틈(Time Gap) 존재result = atomicInteger.compareAndSet(getValue, getValue + 1); // ✅ 원자적 // ← 이 시점에서 다른 스레드가 값을 변경할 수 있음 return atomicInteger.get(); // ❌ 별개의 연산, 원자성 보장 안됨 2. 스레드 스케줄링의 불확실성sleep(100) 동안 CPU가 다른 스레드로 전환CAS 성공 직후에도 스케줄러가 해당 스레드를 중단시킬 수 있음먼저 시작된 스레드가 먼저 완료된다는 보장 없음 📊 실제 문제 시나리오초기값: atomicInteger = 0 Thread A: getValue = 0 Thread A: compareAndSet(0, 1) 성공! → atomicInteger = 1 Thread A: CPU 스케줄러에 의해 중단됨 Thread B: getValue = 1 Thread B: compareAndSet(1, 2) 성공! → atomicInteger = 2 Thread A: 재개됨 Thread A: atomicInteger.get() 호출 → 2 반환 ❌ 결과: Thread A가 실제로는 0→1로 증가시켰지만, 2를 반환하게 됨 ✅ 올바른 해결책: getValue + 1 사용동작 원리private static int incrementAndGet(AtomicInteger atomicInteger) { int getValue; boolean result; do { getValue = atomicInteger.get(); // 현재값 저장 result = atomicInteger.compareAndSet( // CAS 연산 getValue, getValue + 1 ); } while (!result); return getValue + 1; // CAS에서 사용한 기댓값 + 1 } 장점CAS 연산 시점의 값 고정: getValue는 CAS 연산에서 사용한 정확한 기댓값다른 스레드 개입 무관: 이후 다른 스레드가 값을 어떻게 변경하든 영향받지 않음메서드 의미 보장: "이 메서드가 실제로 설정한 값"을 정확히 반환 🎯 핵심 교훈❌ 잘못된 가정"CAS 성공 후 바로 get()을 호출하면 방금 설정한 값을 가져올 것이다" ✅ 올바른 이해원자성은 단일 연산에만 적용연산 간의 순서나 연속성은 보장되지 않음멀티스레드 환경에서는 언제든지 다른 스레드가 개입 가능개발자는 OS가 중간에 어떤 스레드를 호출할지 알 수 없음 💡 실무 적용점AtomicInteger의 내장 메서드 활용// 직접 구현하지 말고 내장 메서드 사용 int result = atomicInteger.incrementAndGet(); CAS 패턴 사용 시 주의사항연산 결과는 CAS에서 사용한 값을 기준으로 계산별도의 get() 호출로 "현재값"을 가져오려 하지 말 것원자성의 범위 명확히 이해단일 메서드 호출 = 원자적여러 메서드 호출의 조합 = 원자적이지 않음
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
오타 제보입니다.
11. 동시성 컬렉션 PDF 13 페이지당연한 이야기지만 다음과 같이 나누어 작성해도 된다.SimpleList basicList = new BasicList(); SimpleList proxyList = new SyncProxyList(basicList); test(list)강의 5:40 즈음 나오는 내용입니다. test() 에 proxyList 가 인자로 전달되어야하는데 pdf에는 test(list) 로 작성되어있네요. 감사합니다
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
멀티스레드일 때 테스트 결과 공유
영한님이 단일 스레드일 때 테스트 하셨는데요.멀티 스레드일 때 테스트 결과도 궁금하신 분들이 있을 것 같아 공유 드립니다 :)빠른 테스트를 위해서 sleep 은 사용하지 않았습니다. public class IncrementPerformanceMain { public static final int COUNT = 1_000_000; public static void main(String[] args) throws InterruptedException { test(new BasicInteger()); test(new VolatileInteger()); test(new SyncInteger()); test(new MyAtomicInteger()); } private static void test(IncrementInteger incrementInteger) throws InterruptedException { long startMs = System.currentTimeMillis(); Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i < COUNT; i++) { incrementInteger.increment(); } } }; ArrayList<Thread> threads = new ArrayList<>(); for (int i = 0; i < 100; i++) { Thread thread = new Thread(runnable); threads.add(thread); thread.start(); } for (Thread thread : threads) { thread.join(); // 모든 스레드가 종료 될 때 까지 기다림 } long endMs = System.currentTimeMillis(); System.out.println( incrementInteger.getClass().getSimpleName() + ": ms=" + (endMs - startMs) + ", result=" + incrementInteger.get()); } } 결과 BasicInteger: ms=32, result=88652038 VolatileInteger: ms=3653, result=17721836 SyncInteger: ms=4882, result=100000000 MyAtomicInteger: ms=6953, result=100000000 MyAtomicInteger 보다 SyncInteger 가 성능이 좋은 이유는 CAS 는 기본적으로 락보다는 빠르지만, 경쟁이 심하면 CAS 실패로 재시도를 반복하기 때문에 성능이 락보다 안나오고 있는 것으로 보이네요.추가로 BasicInteger 에 비해서 VolatileInteger 의 손실율이 큰 이유는 모두가 동시에 메인 메모리에 접근하게 되면서 발생한 문제로 보이네요. 비유적으로 설명하면BasicInteger: 각자 수첩(캐시)에 메모하고 나중에 합침→ 충돌 적고, 결과는 꽤 괜찮음 (운이 좋으면)VolatileInteger: 100명이 하나의 화이트보드(메인 메모리)에 동시에 적으려는 상황→ 끊임없는 덮어쓰기, 충돌 많음 → 결과는 엉망 감사합니다. ^0^
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
join 질문입니다.
thread1.join(); thread2.join();메인스레드 내에서 thread1,2를 join()을 하는데요.thread1.join()을 먼저 만났으니 메인 스레드는 thread1이 종료 될때까지 다음 코드를 실행하지 않을텐데요.여기서 메인스레드가 thread1의 결과를 기다리는 것이므로 thread1,2는 무관하게 그대로 번갈아가며 실행 되는 것이 맞나요? CPU((코어)가 1개라고 가정했을때요.그래서 메인은 thread1이 종료되고 결과를 기다릴뿐 thread1과 2의 종료 순서는 보장되지않는 것이 맞을까요?따라서 thread2가 먼저 작업을 끝낸 실행일 때도 있을 수 있겠죠? 단지 메인이 thrad1의 결과를 먼저 받으려고 기다릴뿐인거죠?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
notify(), notifyAll()
각각 3개로 한정된 소비자, 생산자 스레드가 있습니다. 생산자가 생산자를 깨운 것 처럼 notify()로 일어난 스레드가 다시 wait() 해야하는 경우 락을 반납하고 대기 상태에 든다면 이후 다시 notify()하는 스레드가 없기 때문에 교착상태가 발생하는건가요? (새롭게 추가되는 여러 스레드가 있다면 해결될 가능성도 있으나 새롭게 추가되지 않는 한정된 상황이라면 교착상태가 발생할 수 있으니 notifyAll() 사용이 올바른 선택인지 궁금합니다)
-
해결됨김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
원자적 연산의 의미
원자적 연산의 의미가, i = 1;과 같이 한번의 수행으로 끝나는 동작이지만 넓은 의미에서는 일종의 트랜잭션처럼,여러 코드뭉치지만 하나의 연산으로 취급할 때에도 사용되나요? (강의 2:14참고)
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
join() 위치
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요 아직 끝까지 듣지 않았는데 궁금해서 질문 드립니다. volatile을 사용한 뒤에 메인에서 t1.start() 바로 뒤에 t1.join()이 오게 위치를 변경해주면 t1.start() 가 끝난뒤에 t2.start()가 시작이 되서 balance 값이 변경된 상태로 t2 스레드가 검증에서 false값이 걸리는줄 알았는데.. 이렇게 해도 문제가 발생하는데 그 이유가 궁금합니다.
-
해결됨김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
volatile
안녕하세요 영한쌤!질문드립니다! 쓰레드별로 공유 자원에 대해 효율적인 연산 처리를 위해 캐시 메모리를 사용한다고 하셨습니다! 이러한 문제가 메모리 가시성 문제를 일으킬 수 있어 volatile 키워드로 캐시가 아닌 메인 메모리에 직접 접근할 수 있었습니다. 이번 예제의 경우,volatile이 없었던 가장 기본 BasicInteger는 volatile을 사용하지 않았어도 어느정도 값 수정이 되었는데 이는 캐시 메모리를 사용하지만 컨텍스트 스위칭이 발생하면서 캐시메모리가 메인메모리로 반영하고 다시 이를 읽어오니 반영이 된건가요?(이전에 interrupt를 boolean flag + volatile로 해결하던 예제에서는 컨텍스트 스위칭이 발생할 시기가 확정적이지 않다고 하셨는데 그거에 비해 꽤 많이 연산이 이뤄진것같습니다...)
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
스레드 실행 위치 관련 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]섹션 5의 <프린터 예제3 - 인터럽트 코드 개선 관련> 질문입니다.printer.addJob(input) 관련하여, 어떤 스레드에서 어디서부터 어디까지 책임지고 실행하는지 헷갈려서 정리해봤는데 검토해주시면 감사하겠습니다. === printer.addJob(input) 은 main 스레드(호출 스택)에서 실행된다.공유하는 Heap 메모리 영역에 Printer 객체 주소가 있다.main 스레드는 Printer 객체의 jobQueue 변수에도 접근이 가능하고 addJob() 메서드를 호출할 수 있다.따라서, addJob() 메서드에 대한 스택 프레임도 main 스레드(호출 스택)에 쌓여서 처리된다. === JPA 이후 오랜 만에 영한님 강의를 다시 듣기 시작했는데 재밌네요. 늘 감사합니다.
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
2:33초의 강의 내용
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]2:33초의 강의 내용 중 비효율이 있을 뿐 로직은 모두 정상 작동한다. 이 부분 말씀이 그냥 소비자가 소비자를 깨우는 상황에도 예를 들어 put(), take() 안의 로직이 작동한다는 거죠? 만약 생성자나 소비자가 같이 대기 하고 있을 때 같은 종류의 스레드만 계속해서 깨울 시에 starvation이 발생할 수 있는 것과는 이야기와는 별개인거 맞을까요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
executor service를 스프링에서 이용한다면 어떻게 관리하는게 좋은가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]실무에서 강의를 수강하기 이전에 자바에서 제공하는 executor service를 사용하여 병렬로 프로그램을 짠 경험이 있는데요.저는 spring boot를 사용하여 service 내부에 executors의 고정스레드풀을 사용하여 특정 서비스를 호출할때마다 생성하도록 했습니다.예를 들면, List<?> methodA(req) { ExecutorService es = Executors.newFixedThreadPool(10); List<CompletableFutures> tasks ... // 비즈니스로직 finally{ // shutdown 로직}}공통으로 executor 서비스를 관리하는 클래스를 만들어서 사용해야할까요? 우선 제가 개발한 환경에서는 executor service를 저만 사용했습니다.만약 위에 제가 작성한대로 methodA를 호출할 때마다 쓰레드 풀이 생성되는거 같은데 맞을까요? 이런 방식보다 더 효율적으로 쓰레드를 관리하고 정리할 수 있는지 궁금합니다.
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
tryLock 이후 InterruptedException 발생
락을 얻고 그 후에 InterruptedException이 발생 한다면 finally 에 unlock 을 작성 해 주어야 하나요 ?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
영한님, sleep(10) 이유가 궁금합니다.
안녕하세요. 영한님 궁금한 점이 있습니다.sleep(10) 를 하면 동시 실행을 더 촉진할 수 있다는 것이 이해가 안됩니다. 예를 들어, 아래를 가정한다면요! 각 시간은 별도로 가정한 것입니다. 1번 쓰레드가 1.0초에 먼저 실행이 된 후 0.1 초 쉬었다가 실행이 되면 1.1초에 실행 가정,2번 쓰레드가 1.1초에 먼저 실행이 된 후 0.1 초 쉬었다가 실행이 되면 1.2초에 실행 가정,3번 쓰레드가 1.2초에 먼저 실행이 된 후 0.1 초 쉬었다가 실행이 되면 1.3초에 실행 가정,... 그렇다면 각 쓰레드가 0.1초씩 쉬었다고 하더라도 결국에는 실행시점이1.1초, 1.2초, 1.3초 다 다르다고 봐도 되지 않나요?뭔가, sleep(10) 을 빠지게 되면 대부분 쓰레들이 비슷한 시점에 10ms 를 자고, 거의 동시에 깨어나서 increment() 를 실행하는 것 같은데 맞나요?맞다면 왜 그런가요? 감사합니다!
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
i = 1 원자적 연산
안녕하세요. 좋은 강의 항상 감사합니다. for문으로 1부터 100부터 돌건데, 그 i 변수값(카운터)이 바깥의 공유 변수에 그대로 대입(이퀄 연산) 하는데. 이런 쓰레드가 있는데 100개가 있는데 동시에 같은 로직으로 동일한 공유 변수에 접근을 하는 상황이다. 더하기 연산을 하는 것이 아니다. 이 프로그램이 끝나면 이 공유변수에는 몇의 값 ?i = 1 처럼 원자적 연산일 경우, 멀티스레드 환경에서 문제가 되지 않는다고 하셨잖아요. 그러면 위의 상황에서도 무조건 100이 들어간다고 봐도 되죠?실제로 테스트 해봤을 때도 100이 계속 들어가긴 합니다. 감사합니다.