여러 스레드를 시작하고 완료 시점을 안전하게 기다립니다.
Thread는 Runnable 작업을 별도 실행 흐름에서 수행합니다. start는 새 스레드를 시작하고 join은 해당 스레드가 끝날 때까지 현재 흐름을 기다립니다.
두 스레드를 start한 뒤의 출력 순서는 운영체제의 스케줄링에 달려 있어서 첫 작업과 둘째 작업은 실행할 때마다 순서가 바뀔 수 있습니다. 반면 main은 first.join()과 second.join()에서 두 스레드가 끝날 때까지 멈춰 있으므로 모두 완료는 언제나 마지막 줄에 나옵니다. join은 InterruptedException을 던질 수 있어 main 선언에 throws Exception이 붙어 있습니다.
실무에서는 작업마다 Thread를 직접 만들기보다 ExecutorService로 수명과 동시 실행 수를 제한합니다. interrupt를 받으면 정리하고 필요하면 상태를 복원합니다.
공유 상태를 여러 스레드가 바꾸면 가시성과 원자성 문제가 생기므로 불변 데이터나 동시성 도구를 사용합니다.
run을 직접 호출하면 새 스레드가 시작되지 않고 현재 스레드에서 동기 실행됩니다.
직접 바꿔보세요세 번째 스레드를 추가하고 세 작업이 끝난 뒤 완료 문구가 출력되게 하세요.
실행 버튼을 누르면 결과가 여기에 표시됩니다.