묻고 답해요
154만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
순위 정보를
불러오고 있어요
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
ReentrantLock과 sleep()에 대해 질문 있습니다.
ReentrantLock 사용시 쓸 수 있는 락이 여러 개 있는지 아니면 하나만 쓸 수 있는지 궁금합니다.Object의 wait() 사용 시 스레드가 스레드 대기 공간에서 기다리는 것처럼 sleep() 같은 경우도 따로 대기하는 공간이 있는지 궁금합니다.
-
미해결성공적인 진짜 iOS 개발자 되기 [기초부터 실무까지]
에러 질문 [UITextField setDataSource:]: unrecognized selector sent to instance 0x107079600"
강의 수강 중 35분 정도까지 따라한 뒤 실행했는데, 다음 에러가 발생했는데 이유를 잘 모르겠습니다. 다음처럼 에러가 발생하였는데요. 에러 내용과 작성한 코드들 첨부드립니다. Exception NSException * "-[UITextField setDataSource:]: unrecognized selector sent to instance 0x107079600" 0x0000600000c9d170 에러 전체 내용 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITextField setDataSource:]: unrecognized selector sent to instance 0x107079600' *** First throw call stack: ( 0 CoreFoundation 0x00000001804b70ec __exceptionPreprocess + 172 1 libobjc.A.dylib 0x000000018008ede8 objc_exception_throw + 72 2 CoreFoundation 0x00000001804ccc54 +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0 3 UIKitCore 0x0000000185ace7a8 -[UIResponder doesNotRecognizeSelector:] + 232 4 CoreFoundation 0x00000001804bb3ec ___forwarding___ + 1268 5 CoreFoundation 0x00000001804bdb0c _CF_forwarding_prep_0 + 92 6 CurrencyConverterApp.debug.dylib 0x000000010508d1ec $s20CurrencyConverterApp20PickerViewControllerC11viewDidLoadyyF + 648 7 CurrencyConverterApp.debug.dylib 0x000000010508d270 $s20CurrencyConverterApp20PickerViewControllerC11viewDidLoadyyFTo + 36 8 UIKitCore 0x000000018533369c -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 80 9 UIKitCore 0x0000000185338238 -[UIViewController loadViewIfRequired] + 908 10 UIKitCore 0x000000018529db34 -[UINavigationController _ensureToViewControllersViewIsLoaded:] + 84 11 UIKitCore 0x000000018529df70 -[UINavigationController transitionConductor:willTransitionFromViewController:toViewController:] + 184 12 UIKitCore 0x0000000185c35c70 -[_UIViewControllerTransitionConductor startDeferredTransitionIfNeeded] + 452 13 UIKitCore 0x00000001852951a4 -[UINavigationController __viewWillLayoutSubviews] + 80 14 UIKitCore 0x000000018527cf58 -[UILayoutContainerView layoutSubviews] + 168 15 UIKitCore 0x000000018601c0c4 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2404 16 QuartzCore 0x000000018b06ceb0 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 432 17 QuartzCore 0x000000018b077c34 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 124 18 QuartzCore 0x000000018afacc58 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 464 19 QuartzCore 0x000000018afdb468 _ZN2CA11Transaction6commitEv + 652 20 UIKitCore 0x0000000185abb7b4 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 32 21 CoreFoundation 0x000000018041b0ec __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20 22 CoreFoundation 0x000000018041a824 __CFRunLoopDoBlocks + 352 23 CoreFoundation 0x00000001804150c8 __CFRunLoopRun + 812 24 CoreFoundation 0x0000000180414960 CFRunLoopRunSpecific + 536 25 GraphicsServices 0x0000000190183b10 GSEventRunModal + 160 26 UIKitCore 0x0000000185aa2b40 -[UIApplication _run] + 796 27 UIKitCore 0x0000000185aa6d38 UIApplicationMain + 124 28 UIKitCore 0x0000000184e9a184 block_destroy_helper.22 + 9660 29 CurrencyConverterApp.debug.dylib 0x000000010508820c $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 120 30 CurrencyConverterApp.debug.dylib 0x0000000105088184 $s20CurrencyConverterApp0C8DelegateC5$mainyyFZ + 44 31 CurrencyConverterApp.debug.dylib 0x0000000105088288 __debug_main_executable_dylib_entry_point + 28 32 dyld 0x00000001050dd410 start_sim + 20 33 ??? 0x0000000104e1e274 0x0 + 4376879732 ) libc++abi: terminating due to uncaught exception of type NSException AppDelegate.swift// // AppDelegate.swift // CurrencyConverterApp // // Created by hojeongpark on 9/24/24. // import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } PickerViewController.swift// // ViewController.swift // CurrencyConverterApp // // Created by hojeongpark on 9/24/24. // import UIKit class PickerViewController: UIViewController { var rates: [(String, Double)]? @IBOutlet weak var currencyPicker: UIPickerView! override func viewDidLoad() { super.viewDidLoad() self.navigationItem.title = "Currency List" currencyPicker.delegate = self currencyPicker.dataSource = self fetchJson() } func fetchJson() { let urlString = "https://open.er-api.com/v6/latest/USD" guard let url = URL(string: urlString) else { return } print("fetchJson") // data task URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data else { return } do { let currencyModel = try JSONDecoder().decode(CurrencyModel.self, from: data) self.rates = currencyModel.rates?.sorted{ $0.key < $1.key } // 피커 새로고침 해야 데이터 내용이 보입니다. DispatchQueue.main.async { self.currencyPicker.reloadAllComponents() } print("currencyModel", currencyModel) }catch{ print("error", error) } }.resume() } } extension PickerViewController: UIPickerViewDelegate, UIPickerViewDataSource { func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return rates?.count ?? 0 } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return rates?[row].0 } }
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
ReentrantLock 과 Condition 에 대해 질문 있습니다.
public class BoundedQueueV4 implements BoundedQueue { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private final Queue<String> queue = new ArrayDeque<>(); private final int max; public BoundedQueueV4(int max) { this.max = max; } @Override public void put(String data) { lock.lock(); try { while (queue.size() == max) { log("[put] 큐가 가득 참, 생산자 대기"); try { condition.await(); log("[put] 생산자 깨어남"); } catch (InterruptedException e) { throw new RuntimeException(e); } } queue.offer(data); log("[put] 생산자 데이터 저장, notify() 호출"); condition.signal(); } finally { lock.unlock(); } } @Override public String take() { lock.lock(); try { while (queue.isEmpty()) { log("[take] 큐에 데이터가 없음, 소비자 대기"); try { condition.await(); log("[take] 소비자 깨어남"); } catch (InterruptedException e) { throw new RuntimeException(e); } } String data = queue.poll(); log("[take] 소비자 데이터 획득, notify() 호출"); condition.signal(); return data; } finally { lock.unlock(); } } @Override public String toString() { return queue.toString(); } }synchronized를 사용 했을때는 객체가 기본적으로 가지고 있는 락과 스레드 대기 공간을 사용하는거 같습니다. 궁금한점은 ReentrantLock 객체를 생성하고 Condition 객체를 생성하면 BoundedQueueV4 내부에 또 다른 락과 스레드 대기 공간이 생성 되는건가요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
notify() 호출 후의 상황에 대해 질문 있습니다.
@Override public synchronized void put(String data) { while (queue.size() == max) { log("[put] 큐가 가득 참, 생산자 대기"); try { wait(); // RUNNABLE -> WAITING, 락 반납 log("[put] 생산자 깨어남"); } catch (InterruptedException e) { throw new RuntimeException(e); } } queue.offer(data); log("[put] 생산자 데이터 저장, notify() 호출"); notify(); // 대기 스레드, WAIT -> BLOCKED }생산자 스레드가 먼저 실행되면 마지막 스레드는 wait() 호출 후 스레드 대기 집합에서 관리 되는걸로 이해했습니다.이 상태에서 소비자 스레드가 실행되면 데이터를 처리하고 마지막에 notify()를 호출하면 스레드 대기 집합에서 관리 되던 생산자 스레드가 깨어날텐대 여기서 wait(); 바로 다음 코드를 실행하지 않고 바로 BLOCKED 상태가 되는건가요?BLOCKED 상태에 있다가 소비자 스레드가 락을 반납 했을때 BLOCKED 상태가 풀리면서 wait() 바로 다음 코드를 실행한다고 이해하면 될까요?
-
미해결성공적인 진짜 iOS 개발자 되기 [기초부터 실무까지]
Main interface 지정 방법
안녕하세요. 강의 중에 설명해주시는 내용 중 Development info > Main interface 설정하는 부분이 안보여서 질문드립니다. 최신 xcode, mac 버전을 사용하고 있어 업데이트가 된 거 같은데 어디에서 설정할 수 있을까요? 강의 중 화면 제 화면.
-
미해결실전! Django 활용
urls.py 파일에 작성한 코드 분리 여부
안녕하세요. 정말 강의 재밌게 잘 듣고 있습니다.들으면서 궁금한 부분이 있어 질문드립니다./orders API를 예시로 들었을 때, urls.py 파일에 모든 코드가 작성되는데, 쿼리나 비즈니스 로직을 따로 분리하는 방식은 파이썬 프레임워크에서는 잘 사용하지 않는 방법인가요? 일반적으로 스프링에서는 service와 respository 클래스로 해당 코드를 분리하는 편이어서 이 차이점이 궁금합니다.
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
비관적 락 vs 레디스(Lettuce)락 비교 관련 질문
강의를 보고 제 사이드 프로젝트에 그대로 적용해 보았습니다. 리뷰와 리뷰댓글 테이블이 있으면 동시에 1번 리뷰에 대한 리뷰댓글을 100개 썼을때, 리뷰테이블의 리뷰댓글카운트 컬럼에 업데이트를 시키는데, 두 방식 다 성공했습니다.처리시간 평균비관적 락 : 1초레디스 락 : 1.5초 환경은 리뷰테이블에는 데이터 2건, 리뷰댓글테이블에는 10만건 있었습니다.시도해본것레디스 락의 락 유지시간, 재시도 시간을 줄여봄Q1. 그렇다면 어떤 환경에서는 레디스 락이 빠를까요?Q2. 레디스 락이 분산 시스템 환경에서 유리하다는데 그것에 대해서도 설명 부탁드립니다.Q3. 곧 MSA 프로젝트를 하는데 각 마이크로 서비스마다 DB가 있을테고 각 서비스에 DB에 접근할때 비관적 락을 걸어도 문제없을거 같은데 이때에 레디스 락을 쓰는 것에 대한 장점이 있을까요??
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
문자열 풀 값을 이용한 String 변수
강의에서 각 스레드 스택 마다 지역변수로 objectReference 참조 변수를 생성하시는 것을 예시로 들어주셧는데요, 해당 변수는 문자열 풀 값들을 이용해서 만들어진 것이잖아요.힙에 저장될 때 어떻게 데이터가 저장되나요? thread 1번에서 생성한 지역변수인 objectReference 는"1" 의 문자열 풀 주소값 + ": Hello World" 의 문자열 풀 주소값, thread 2번에서 생성한 지역변수인 objectReference 는"2" 의 문자열 풀 주소값 + ": Hello World" 의 문자열 풀 주소값,...이렇게 저장되는 것이 맞을까요?? 혹은 "1 : Hello World" 라는 문자열 전체가 하나의 스트링 풀에 저장되고, 그 상수에 대한 주소값이 저장되는 것일까요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
synchronized 코드블록에서 사용하는 파라미터의 존재 이유
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]synchronized (){} 블록에서 파라미터로 인스턴스를 지정하는 이유가 혹시 다른 클래스에 있는 메서드와의 동시성 연결..? 때문일까요?예를 들어 이러한 사고 실험을 해보았습니다)A 클래스에 a 메서드를 실행하면 해당 메서드에서 내부적으로B 클래스에 b 메서드를 실행한다고 가정을 하겠습니다. 하지만 b 메서드는 a 메서드를 통해서만 호출되는 것이 아니라 자체적으로도 호출하는 메서드라고 했을 때, 나타나는 동시성을 고려한 것일까 의문이 들었습니다. 그렇다고 한다면,b 메서드 안에 synchronized (b 클래스의 인스턴스) {} 를 지정하여,a 메서드를 통해 호출되는 b 메서드와 B 클래스 자체적으로 호출하는 b 메서드의 동시성 문제를 해결할 수 있겠다 예상이 됩니다. synchronized 블록의 파라미터는 위와 같은 상황을 위해 특정 인스턴스의 락을 파라미터로 잡게 한건가요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
Thread.yield() 는 컨텍스트 스위칭을 일으키는 걸까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]강의에서 ,Cache 메모리 값을 초기화하는데 제일 확실한 방법이 컨텍스트 스위칭이라고 하셨습니다.그럼 while 문 안에 Thread.yield()를 통해 Running 에서 Ready로 바꾸면 되지 않을까? 생각이들어 직접해보니 바로 꺼지는 것을 확인했습니다. 여기서 의문이 들었습니다. Thread.yield()를 하게되면 컨텍스트 스위칭을 하는 걸까요?
-
미해결성공적인 진짜 iOS 개발자 되기 [기초부터 실무까지]
Closure_3 Capture List에 참조 타입 값을 작성할 경우에도 deinit 실행되는 이유가 뭘까요?
import UIKit class TestClass {} class SomeClass { var a = 10 var b = TestClass() func myFunc() { print(self.a) } lazy var myClosure1: (()->Void)? = { () -> Void in print(self.a) } lazy var myClosure2 = { [a] () -> Void in print(a) } lazy var myClosure3 = { [b] in print(b) } deinit { print("SomeClass deinit") } } var myClass1: SomeClass? = SomeClass() var myClass2 = myClass1 var myClass3 = myClass1 var myClass4 = myClass1 myClass1?.myClosure1 myClass1?.myClosure1 = nil myClass1?.myClosure2 myClass1?.myClosure3 myClass1 = nil myClass2 = nil myClass3 = nil myClass4 = nil위 코드에서 myClusore3 의 캡쳐 리스트엔 b를 작성했고, b는 클래스의 인스턴스로 참조타입으로 알고 있습니다.이 때 위 코드를 실행하면 deinit이 실행되는데요. weak 키워드를 사용하지 않았는데도 deinit이 실행되는 이유가 있을까요?
-
해결됨김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
Yield 를 사용한 후 currentThread
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요. public void run() { while (!Thread.interrupted()) { if (jobQueue.isEmpty()) { Thread.yield(); continue; } ... }위에 코드에서 Yield 를 사용하면 그 쓰레드가 양보를 해서 다시 스케쥴러로 들어간다고 하셨는데, 그러면 Thread.yield(); 가 실행이 된 후에, 다시 CPU 가 이 쓰레드를 실행시키기 전까지 그 다음 줄의 continue 코드는 실행되지 않고 멈춰있는 상태라고 생각하면 될까요? 그렇다면 쓰레드는 CPU 가 다시 실행시킬 시점에 몇번째 라인까지 실행을 했는지 기억하고 있다가 CPU 에게 알려주는 건가요? 감사합니다.
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
강의 이미지에 대해 질문 있습니다.
그림에서 main 스레드 안에 CPU 코어 1이 있는데 이 상황을 CPU 코어 1에 main 스레드가 할당 됐고 CPU 코어 1은 main 스레드의 스택 영역과 main 스레드가 속해 있는 프로세스의 코드, 데이터, 힙 영역에 접근해서 값을 가져다가 연산한다 라고 이해를 하면 될까요? CPU 내부에 존재하는 레지스터와 위 이미지의 캐시 메모리는 역할이 다르다고 보면 될까요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
자바 스레드와 커널 스레드에 대해 질문 있습니다.
기존 Java의 스레드 모델은 Native Thread로, Java의 유저 스레드를 만들면 Java Native Interface(JNI)를 통해 커널 영역을 호출하여 OS가 커널 스레드를 생성하고 매핑하여 작업을 수행하는 형태로 알고 있습니다.앞서 얘기 해주신 Thread를 상속해서 만든 스레드와 Runnalbe을 사용해서 만든 스레드가 Java의 유저 스레드인지 궁금합니다.Thread thread1 = new Thread(runnable) 이런식으로 스레드를 생성 했을때 메모리의 힙 영역에 thread1이 저장되고 thread1을 위한 스택 영역이 생성된다고 보면 될까요?OS가 생성한 커널 스레드는 메모리 어디에 저장 되는지 궁금합니다.JVM은 JNI라는 기술을 사용해 자바의 유저 스레드와 커널 스레드를 매핑 해주는 작업만 해주고 이후에 스레드 관리는 OS가 하는건지 궁금합니다. 스레드를 생성할때마다 해당 스레드를 위한 스택 영역이 생성된다고 하셨는데 이때 커널 스레드를 위한 스택도 만들어지는 건지 아니면 커널 스레드가 유저 스레드의 스택 영역을 가져다 쓰는건지 궁금합니다.
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
스레드 라이브러리는 커널과 같은 역할을 하지 못하나요?
강의와 다른 질의응답을 확인하였을 때, 사용자 수준에서 사용자 레벨 스레드 생성을 스레드 라이브러리가 관리하고, 관리의 범위는 스레드의 생성 및 소멸, 스케쥴링, 컨텍스트 스위칭을 할 수 있다고 말씀해주셨습니다! 그런데 다대일 스레드 매핑 모델의 특징에서 한 프로세스에 속해있는 사용자 수준 스레드들 중 하나가 block되면 프로세스 전체가 block이 되는데, 이는 커널에서 프로세스가 가지고 있는 개별적인 스레드를 인지하지 못하고, 그냥 하나의 스레드로 인지해서 대체할 스레드를 찾지 못함이라고 질의응답에서 확인 하였는데요, 강의 내용대로 스레드 라이브러리가 사용자 스레드를 관리하기 위해 많은 작업을 하고 있는데, 사용자 스레드 라이브러리에서 사용자 수준 스레드 중 일부가 블락되었을 때 커널 대신 다른 대기 중인 스레드를 ready > run 상태로 변경할 수는 없는 건가요?
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
부모쓰레드 개념 질문입니다.
안녕하세요, 강의 중, 모든 쓰레드는 직접적으로 만들 수 없고메인쓰레드에 의해서 생성이 된다고 하셨던 부분에 대해서 궁금한 점이 있어서 질문을 남깁니다. 자바 말고 스프링의 경우에도 1개의 메인쓰레드가 N개의 요청에 따른 스레드를 생성해주는 구조일까요? 요청당 1개의 스레드를 차지하는데 이 경우에는 어떻게 되는지 궁금합니다 ~
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
56강에 대한 질문입니다(BoundedMain).
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]package thread.bounded; import static util.MyLogger.log; public class ProducerTask implements Runnable { private BoundedQueue queue; private String request; public ProducerTask(BoundedQueue queue, String request) { this.queue = queue; this.request = request; } @Override public void run() { log("[생산 시도] " + request + " -> " + queue); log("[생산 완료] " + request + " -> " + queue); } }package thread.bounded; import static util.MyLogger.log; public class ConsumerTask implements Runnable { private BoundedQueue queue; public ConsumerTask(BoundedQueue queue) { this.queue = queue; } @Override public void run() { log("[소비 시도] ? <- " + queue); String data = queue.take(); log("[소비 완료] " + data + " <- " + queue); } }package thread.bounded; public interface BoundedQueue { void put(String data); String take(); }package thread.bounded; import java.util.ArrayList; import java.util.List; import static util.MyLogger.log; import static util.ThreadUtils.sleep; public class BoundedMain { public static void main(String[] args) { // 1. BoundedQueue 선택 BoundedQueue queue = new BoundedQueueV1(2); // 2. 생산자, 소비자 실행 순서 선택, 반드시 하나만 선택! producerFirst(queue); // 생산자 먼저 실행 //consumerFirst(queue); // 소비자 먼저 실행 } private static void producerFirst(BoundedQueue queue) { log("== [생산자 먼저 실행] 시작, " + queue.getClass().getSimpleName() + " =="); List<Thread> threads = new ArrayList<>(); startProducer(queue, threads); printAllState(queue, threads); startConsumer(queue, threads); printAllState(queue, threads); log("== [생산자 먼저 실행] 종료, " + queue.getClass().getSimpleName() + " =="); } private static void consumerFirst(BoundedQueue queue) { log("== [소비자 먼저 실행] 시작, " + queue.getClass().getSimpleName() + " =="); List<Thread> threads = new ArrayList<>(); startConsumer(queue, threads); printAllState(queue, threads); startProducer(queue, threads); printAllState(queue, threads); log("== [소비자 먼저 실행] 종료, " + queue.getClass().getSimpleName() + " =="); } private static void startProducer(BoundedQueue queue, List<Thread> threads) { System.out.println(); log("생산자 시작"); for (int i = 1; i <= 3; i++) { Thread producer = new Thread(new ProducerTask(queue, "data" + i), "producer" + i); threads.add(producer); producer.start(); sleep(100); } } private static void startConsumer(BoundedQueue queue, List<Thread> threads) { System.out.println(); log("소비자 시작"); for (int i = 1; i <= 3; i++) { Thread consumer = new Thread(new ConsumerTask(queue), "consumer" + i); threads.add(consumer); consumer.start(); sleep(100); } } private static void printAllState(BoundedQueue queue, List<Thread> threads) { System.out.println(); log("현재 상태 출력, 큐 데이터: " + queue); for (Thread thread : threads) { log(thread.getName() + ": " + thread.getState()); } } }package thread.bounded; import java.util.ArrayDeque; import java.util.Queue; import static util.MyLogger.log; public class BoundedQueueV1 implements BoundedQueue { private final Queue<String> queue = new ArrayDeque<>(); private final int max; public BoundedQueueV1(int max) { this.max = max; } @Override public synchronized void put(String data) { if (queue.size() == max) { log("[put] 큐가 가득 참, 버림: " + data); return; } queue.offer(data); } @Override public synchronized String take() { if (queue.isEmpty()) { return null; } return queue.poll(); } @Override public String toString() { return queue.toString(); } }C:\Users\lgh80\.jdks\temurin-21.0.4\bin\java.exe --enable-preview "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.4\lib\idea_rt.jar=52674:C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.4\bin" -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath C:\java-adv1\out\production\java-adv1 thread.bounded.BoundedMain09:38:16.411 [ main] == [생산자 먼저 실행] 시작, BoundedQueueV1 ==09:38:16.413 [ main] 생산자 시작09:38:16.424 [producer1] [생산 시도] data1 -> []09:38:16.425 [producer1] [생산 완료] data1 -> []09:38:16.531 [producer2] [생산 시도] data2 -> []09:38:16.532 [producer2] [생산 완료] data2 -> []09:38:16.642 [producer3] [생산 시도] data3 -> []09:38:16.642 [producer3] [생산 완료] data3 -> []09:38:16.752 [ main] 현재 상태 출력, 큐 데이터: []09:38:16.754 [ main] producer1: TERMINATED09:38:16.754 [ main] producer2: TERMINATED09:38:16.754 [ main] producer3: TERMINATED09:38:16.755 [ main] 소비자 시작09:38:16.757 [consumer1] [소비 시도] ? <- []09:38:16.757 [consumer1] [소비 완료] null <- []09:38:16.864 [consumer2] [소비 시도] ? <- []09:38:16.865 [consumer2] [소비 완료] null <- []09:38:16.974 [consumer3] [소비 시도] ? <- []09:38:16.975 [consumer3] [소비 완료] null <- []09:38:17.085 [ main] 현재 상태 출력, 큐 데이터: []09:38:17.085 [ main] producer1: TERMINATED09:38:17.086 [ main] producer2: TERMINATED09:38:17.086 [ main] producer3: TERMINATED09:38:17.086 [ main] consumer1: TERMINATED09:38:17.087 [ main] consumer2: TERMINATED09:38:17.087 [ main] consumer3: TERMINATED09:38:17.087 [ main] == [생산자 먼저 실행] 종료, BoundedQueueV1 ==Process finished with exit code 0이런 식으로 출력이 뜨는데 강의 내용에 나와있는 로그 창이랑 많이 달라서 강의 코드랑도 비교해봤는데 어디에서 문제가 있는 건지 잘 모르겠습니다.
-
미해결김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
인터럽트에 대해 질문 있습니다.
public class ThreadStopMainV2 { public static void main(String[] args) throws InterruptedException { Job job = new Job(); Thread thread = new Thread(job); thread.start(); Thread.sleep(4000); log("작업 중단 지시 interrupt"); thread.interrupt(); log("main 스레드 끝"); } static class Job implements Runnable { @Override public void run() { while (true) { try { log("스레드 실행"); Thread.sleep(2000); } catch (InterruptedException e) { log("예외 발생"); break; } } log("작업 끝"); } } }위 코드의 실행 결과는 아래와 같습니다.궁금한 부분은 로그에서 작업 중단 지시 interrupt 이후에 대해 궁금한점이 있습니다. 작업 중단 지시 interrupt 를 로그로 찍고 thread.interrupt();를 호출 했습니다. 그러면 생선한 스레드에 interrupt 신호를 보내고 Thread.sleep(2000); 부분에서 예외가 발생해 catch 문으로 빠지는것도 이해했습니다. 하지만 catch 문으로 빠지기전 log("스레드 실행"); 가 실행되지 않나 라는 생각이 듭니다. 그래서 최종 결과는 아래와 같이 catch 로 빠지기전에 스레드 실행이 한번 더 찍혀야 하지 않나 라는 생각이 듭니다.23:08:15.622 [ Thread-0] 스레드 실행23:08:17.629 [ Thread-0] 스레드 실행23:08:19.613 [ main] 작업 중단 지시 interrupt23:08:19.613 [ Thread-0] 스레드 실행23:08:19.614 [ main] main 스레드 끝23:08:19.614 [ Thread-0] 예외 발생23:08:19.616 [ Thread-0] 작업 끝
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
낙관적락 vs 네임드락
낙관적락과 다르게 네임드락은 재시도 로직이 필요 없나요?낙관적락은 충돌이 빈번하다면 재시도 로직으로 인해 비관적락보다 성능이 떨어질 수 있는데, 네임드락은 어떤가요?
-
해결됨김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성
this에 대해 질문 있습니다.
객체를 생성하는 순간 힙 영역에 객체가 저장(필드값)된다고 알고 있습니다. 메서드를 호출하기 위해서는 우선 객체를 생성한 후에 메서드를 호출해야 한다고 생각합니다. 궁금한 부분은 언제 메서드 프레임의 this에 값이 저장 되는지 궁금합니다. 메서드 호출 할때 힙 영역에 저장되어 있는 객체의 주소값이 this로 저장이 되는건가요?
주간 인기글
순위 정보를
불러오고 있어요