JavaRush /Java Blog /Random-KO /번역: 스레드별 상위 50개 인터뷰 질문. 1 부.
KapChook
레벨 19
Volga

번역: 스레드별 상위 50개 인터뷰 질문. 1 부.

Random-KO 그룹에 게시되었습니다
신입생, 숙련된 프로그래머를 위한 상위 50가지 Java 스레드 인터뷰 질문 답변 원본 기사 번역의 첫 번째 부분입니다 . 두 번째 부분. 참고: 기사가 큰 것으로 판명되었으므로 하나의 주제에 맞지 않습니다. 게다가 꽤 복잡해서 최선을 다해 구글링해 봤지만 그래도 마찬가지다. 따라서 영어에 능통한 참가자들은 혹시라도 잘못 이해했거나 잘못 번역한 경우가 있으면 원문을 보시고 번역문과 비교해 보시길 바랍니다. 미리 감사드립니다. 선배든 후배든, 경험이 많든 초보자든 모든 인터뷰에서 스레드, 병렬 처리 및 멀티스레딩에 대한 몇 가지 질문에 직면하게 됩니다. 실제로 이러한 내장된 동시성 지원은 Java의 가장 큰 장점 중 하나이며 Java가 기업가와 프로그래머 모두 사이에서 인기를 얻는 데 도움이 되었습니다. 수익성이 가장 좋은 Java 개발자 직위를 얻으려면 뛰어난 멀티스레딩 기술과 고성능, 저지연 애플리케이션 개발, 디버깅 및 튜닝 경험이 필요합니다. 따라서 면접에서 가장 많이 요구되는 기술 중 하나입니다. 일반적인 Java 면접에서는 면접관이 스레드의 기본 개념부터 천천히 시작하여 스레드가 왜 필요한지, 어떻게 생성하는지, 어떤 방식으로 생성하는 것이 좋은지, Thread에서 상속 받거나 Runnable을 구현하는지 등의 질문을 한 후 천천히 진행합니다. 동시성의 어려움, 병렬 애플리케이션 개발 시 직면하는 어려움, JDK 1.5에 도입된 높은 수준의 동시성 유틸리티, 병렬 애플리케이션의 원칙 및 디자인 패턴, 고전적인 멀티스레딩 문제에 대해 설명합니다. 멀티스레딩의 기본을 아는 것만으로는 충분하지 않기 때문에 교착 상태, 경쟁 조건, 메모리 불일치 및 다양한 스레드 안전성 문제와 같은 동시성 문제를 처리하는 방법을 알아야 합니다. 이러한 기술은 철저한 테스트를 거쳐 다양한 멀티스레딩 및 동시성 문제를 제시합니다. 많은 Java 개발자는 일반적으로 인터뷰 전에 질문을 읽는 경우가 많습니다. 이는 나쁜 것은 아니지만 이를 이해해야 합니다. 그리고 질문을 쌓고 똑같은 연습을 하면 시간낭비도 많이 되어서 이 목록을 만들었습니다.
  1. Java의 스레드란 무엇입니까?

  2. 스레드는 독립적인 실행 경로입니다. 그 목표는 시스템에서 사용 가능한 다중 프로세서를 활용하는 것입니다. 다중 스레드를 사용하면 CPU 바인딩된 작업 속도를 높일 수 있습니다. 예를 들어 하나의 스레드가 작업을 완료하는 데 100밀리초가 걸리는 경우 10개의 스레드를 사용하여 해당 작업을 10밀리초로 줄일 수 있습니다. Java는 언어 수준에서 멀티스레딩에 대한 뛰어난 지원을 제공하며 이는 Java의 가장 강력한 장점 중 하나입니다.
  3. Java의 스레드와 프로세스의 차이점은 무엇입니까?

  4. 스레드는 프로세스의 하위 집합입니다. 즉, 하나의 프로세스에 여러 스레드가 포함될 수 있습니다. 두 프로세스는 서로 다른 메모리 공간에서 실행되지만 모든 스레드는 동일한 메모리 공간을 공유합니다. 이것을 스레드마다 다르며 해당 스레드의 로컬 데이터를 저장하는 데 사용되는 스택 메모리와 혼동하지 마십시오.
  5. 스레드를 만드는 방법은 무엇입니까?

  6. 언어 수준에서는 스레드를 만드는 두 가지 방법이 있습니다. java.lang.Thread 클래스의 객체는 스레드를 나타내지만 실행하려면 java.lang.Runnable 인터페이스를 구현하는 객체인 작업이 필요합니다. Thread 클래스는 Runnable 인터페이스를 구현하므로 Thread에서 클래스를 파생시키거나 그 안에 Runnable 인터페이스를 구현하여 run() 메서드를 재정의할 수 있습니다.
  7. 언제 Runnable을 사용하고 언제 Thread를 사용합니까?

  8. 이것은 이전 질문에 대한 추가 내용입니다. 우리가 알고 있듯이 스레드는 Thread 클래스에서 상속하거나 Runnable 인터페이스를 구현하여 생성할 수 있습니다. 어떤 방법이 더 좋고 언제 어떤 방법을 사용해야 하는지에 대한 질문이 생깁니다. Java가 다중 클래스 상속을 지원하지 않지만 다중 인터페이스를 구현할 수 있다는 것을 알고 있다면 이 질문에 쉽게 대답할 수 있습니다. 즉, 다른 클래스에서 상속하려면 Runnable을 구현하는 것이 더 좋습니다.
  9. start()와 run() 메소드의 차이점은 무엇입니까?

  10. 과거의 트릭 질문 중 하나이지만 Java의 멀티스레딩에 대한 피상적인 이해를 구별하는 데는 여전히 충분합니다. start() 메소드는 새로운 스레드를 시작하는 데 사용됩니다. start()가 내부적으로 run() 메서드를 호출하더라도 단순히 run()을 호출하는 것과는 다릅니다. run()을 일반 메소드로 호출하면 동일한 스레드에서 호출되며 새 스레드가 시작되지 않습니다. 이는 start() 메소드를 호출할 때 발생합니다.
  11. 실행 가능과 호출 가능의 차이점은 무엇입니까?

  12. 두 인터페이스 모두 별도의 스레드에서 실행되도록 고안된 작업을 나타냅니다. Runnable은 JDK 1.0부터 있었고 Callable은 JDK 1.5에 추가되었습니다. 가장 큰 차이점은 Callable의 call() 메소드가 값을 반환하고 예외를 발생시킬 수 있다는 점인데, 이는 Runnable의 run() 메소드에서는 가능하지 않습니다. Callable은 계산 결과를 포함할 수 있는 Future 객체를 반환합니다.
  13. CyclicBarrier와 CountDownLatch의 차이점은 무엇입니까?

  14. 두 동기화 장치 모두 스레드가 서로를 기다릴 수 있도록 허용하지만, 두 동기화 장치의 주요 차이점은 카운터가 0에 도달한 후에는 CountDownLatch를 재사용할 수 없지만 장벽이 무너진 후에도 CyclicBarrier를 다시 사용할 수 있다는 것입니다.
  15. Java 메모리 모델이란 무엇입니까?

  16. 메모리 모델은 Java 프로그램이 여러 메모리, 프로세서 및 운영 체제 아키텍처에서 결정론적으로 작동할 수 있도록 하는 일련의 규칙 및 지침입니다. 이는 다중 필라멘트의 경우 특히 중요합니다. 메모리 모델은 한 스레드의 변경 사항이 다른 스레드에 표시되도록 보장하며, 그 중 하나는 사전 발생 관계입니다. 이 관계는 프로그래머가 병렬 프로그램의 동작을 예측하고 결정할 수 있도록 하는 여러 규칙을 정의합니다. 예를 들어 보증이 발생하기 전에 발생하는 경우는 다음과 같습니다.
    • 스레드의 모든 작업은 프로그램 순서 규칙(프로그램 순서 규칙이라고도 함)에 따라 해당 스레드의 모든 작업보다 먼저 발생합니다.
    • 모니터 잠금 해제는 동일한 모니터의 각 후속 잠금(모니터 잠금 규칙이라고도 함) 전에 발생합니다.
    • 휘발성 필드에 대한 쓰기는 휘발성 변수 규칙에 따라 해당 필드를 이후에 읽을 때마다 발생합니다.
    • 스레드에서 Thread.start()에 대한 호출은 Thread.join()이 성공한 후 또는 Thread.isAlive()가 false를 반환하는 경우 Thread.start() 규칙에 따라 스레드가 중지되었음을 다른 스레드가 알기 전에 발생합니다. .
    • 다른 스레드에 의해 중단되는 스레드는 중단된 스레드가 스레드의 중단 규칙인 중단(InterruptedException을 발생시키거나 isInterrupted()를 확인하여)을 인지하기 전에 발생합니다.
    • 개체 생성자의 끝은 해당 개체에 대한 종료자 규칙인 종료자 규칙이 시작되기 전에 발생합니다.
    • A가 B보다 먼저 발생하고 B가 C보다 먼저 발생하면 A가 C보다 먼저 발생합니다. 즉, 전이성이 보장됨을 의미합니다.
  17. 휘발성 변수란 무엇입니까?

  18. 휘발성은 속성에만 적용할 수 있는 특수 수정자입니다. 병렬 Java 프로그램에서는 동기화 장치가 없으면 속성에 대해 서로 다른 스레드에 의해 변경된 내용이 다른 사람에게 표시되지 않습니다. 휘발성 변수는 이전 질문의 휘발성 변수 규칙에 명시된 대로 후속 읽기 전에 쓰기가 발생하도록 보장합니다.
  19. 스레드 안전성이란 무엇입니까? Vector 클래스는 안전한가요?

  20. 스레드 안전성은 여러 스레드에서 실행되거나 사용될 때 코드가 의도한 대로 작동하도록 보장하는 개체 또는 코드의 속성입니다. 예를 들어, 스레드 안전 카운터는 여러 스레드에서 동일한 카운터 인스턴스가 사용되는 경우 카운트를 건너뛰지 않습니다. 분명히 컬렉션 클래스는 스레드로부터 안전한 클래스와 스레드로부터 안전하지 않은 클래스의 두 가지 범주로 나눌 수 있습니다. Vector는 스레드로부터 안전하며 Vector의 상태를 변경하는 메서드를 동기화하여 이를 달성하는 반면, 이에 상응하는 ArrayList는 스레드로부터 안전하지 않습니다.
  21. 경쟁 조건이란 무엇입니까?

  22. 경쟁 조건은 미묘한 버그의 원인입니다. 이름 그대로 여러 스레드 간의 경합으로 인해 경쟁 조건이 발생하는데, 먼저 실행해야 할 스레드가 경쟁에서 지고 두 번째 스레드가 실행되면 코드의 동작이 바뀌어 비결정적 버그가 발생합니다. 이는 스레드 간 경쟁의 지저분한 특성으로 인해 포착하고 재현하기 가장 어려운 버그 중 일부입니다. 경쟁 조건의 예로는 불규칙한 실행이 있습니다.
  23. 스레드를 중지하는 방법은 무엇입니까?

  24. 나는 항상 Java가 모든 것에 대해 풍부한 API를 제공한다고 말했지만 아이러니하게도 스레드를 중지하는 편리한 방법을 제공하지 않습니다. JDK 1.0에는 잠재적인 교착 상태 위협으로 인해 향후 릴리스에서 더 이상 사용되지 않는 것으로 표시된 stop(), suspens() 및 이력서()와 같은 여러 제어 메서드가 있었습니다. 그 이후로 Java API 개발자는 스레드를 제공하려는 시도를 하지 않았습니다. -저항성 -스레드를 멈추는 안전하고 우아한 방법입니다. 프로그래머는 대부분 스레드가 run() 또는 call() 메서드 실행을 마치자마자 자체적으로 중지된다는 사실에 의존합니다. 수동으로 중지하려면 프로그래머는 휘발성 부울 변수를 활용하고 run() 메서드에 루프가 있는 경우 각 반복에서 해당 값을 확인하거나, Interrupt() 메서드로 스레드를 중단하여 작업을 갑자기 취소합니다.
  25. 스레드에서 예외가 발생하면 어떻게 되나요?

  26. 이것은 좋은 트릭 질문 중 하나입니다. 간단히 말해서, 예외가 포착되지 않으면 스레드는 종료되고, 포착되지 않은 예외에 대한 핸들러가 설치되면 콜백을 받게 됩니다. Thread.UncaughtExceptionHandler는 catch되지 않은 예외로 인해 스레드가 갑자기 중지될 때 호출되는 핸들러에 대한 중첩 인터페이스로 정의된 인터페이스입니다. 포착되지 않은 예외로 인해 스레드가 종료되려고 하면 JVM은 Thread.getUncaughtExceptionHandler()를 사용하여 UncaughtExceptionHandler가 있는지 확인하고 핸들러의 uncaughtException() 메서드를 호출하여 스레드와 예외를 인수로 전달합니다.
  27. 두 스레드 간에 데이터를 공유하는 방법은 무엇입니까?

  28. 공유 객체나 BlockingQueue와 같은 병렬 데이터 구조를 사용하여 스레드 간에 데이터를 공유할 수 있습니다.
  29. 통지와 통지All의 차이점은 무엇입니까?

  30. 이것은 또 다른 까다로운 질문입니다. 하나의 모니터가 여러 스레드에 의해 모니터링될 수 있기 때문에 Java API 개발자는 하나 또는 모든 스레드에게 상태 변경을 알리는 방법을 제공하지만 구현의 절반만 제공합니다. inform() 메소드에는 특정 스레드를 선택할 수 있는 방법이 없으므로 단 하나의 스레드만 대기 중임을 확실히 알고 있는 경우에만 유용합니다. 반면에 informal()은 모든 스레드에 알리고 모니터를 두고 경쟁할 수 있도록 하여 최소한 하나의 스레드가 앞으로 이동하도록 합니다.
  31. Thread 클래스에 wait,notify,notifyAll이 없는 이유는 무엇입니까?

  32. 이는 후보자가 기존 시스템에 대해 어떻게 생각하는지 또는 처음에는 어울리지 않는 비슷한 것을 생각해 본 적이 있는지 테스트하는 설계 질문입니다. 이 질문에 대답하려면 이러한 메서드가 Object 클래스에서 더 잘 구현되고 Thread 클래스에서는 구현되지 않는 몇 가지 이유를 제시해야 합니다. 첫 번째 분명한 이유는 Java가 스레드 수준이 아닌 개체 수준에서 잠금을 지원한다는 것입니다. 모든 객체에는 스레드가 획득하는 잠금이 있습니다. 그리고 스레드가 특정 잠금을 기다려야 하는 경우 이 스레드보다 개체에서 wait()를 호출하는 것이 더 합리적입니다. Thread 클래스에서 wait()가 선언된 경우 스레드가 어떤 잠금을 기다리고 있는지 명확하지 않습니다. 즉, wait, inform, informAll은 lock 수준에서 동작하므로 lock은 객체를 참조하므로 Object 클래스에서 선언하는 것이 더 편리하다.
  33. ThreadLocal 변수란 무엇입니까?

  34. ThreadLocal 변수는 Java 프로그래머가 사용할 수 있는 특별한 유형의 변수입니다. 상태에 상태 변수가 있는 것처럼 스레드에는 ThreadLocal 변수가 있습니다. 이는 생성 비용이 많이 드는 개체에 대해 스레드 안전성을 달성하는 좋은 방법입니다. 예를 들어 ThreadLocal을 사용하여 SimpleDateFormat을 스레드로부터 안전하게 만들 수 있습니다. 이는 비용이 많이 드는 클래스이므로 호출마다 별도의 인스턴스가 필요한 로컬 범위에서는 사용하지 않는 것이 좋습니다. 각 스레드에 고유한 복사본을 제공하면 일석이조의 효과를 얻을 수 있습니다. 첫째, 새로운 고정 개수의 인스턴스를 사용하여 값비싼 개체의 인스턴스 수를 줄이고, 둘째, 동기화 및 불변성을 잃지 않고 스레드 안전성을 달성합니다. 스레드 로컬 변수의 또 다른 좋은 예는 다중 스레드 환경에서 생성하는 데 비용이 많이 드는 Random 개체의 인스턴스 수를 줄이는 ThreadLocalRandom 클래스입니다.
  35. 퓨처태스크란 무엇인가요?

  36. FutureTask는 병렬 Java 애플리케이션에서 취소 가능한 비동기 계산입니다. 이 클래스는 계산 시작 및 중지 메서드, 계산 상태 쿼리 및 결과 검색 메서드가 포함된 기본 Future 구현을 제공합니다. 결과는 계산이 완료된 경우에만 얻을 수 있으며 계산이 아직 완료되지 않은 경우 getter 메서드가 차단됩니다. FutureTask 객체는 Callable 및 Runnable 객체를 래핑하는 데 사용될 수 있습니다. FutureTask는 Runnable을 구현하므로 실행을 위해 Executor로 전달될 수 있습니다.
  37. Interrupted와 isInterrupted의 차이점은 무엇입니까?

  38. Interrupted()와 isInterrupted()의 주요 차이점은 전자는 인터럽트 상태를 재설정하지만 후자는 그렇지 않다는 것입니다. Java의 인터럽트 메커니즘은 인터럽트 상태라고 알려진 내부 플래그를 사용하여 구현됩니다. Thread.interrupt()를 호출하여 스레드를 중단하면 이 플래그가 설정됩니다. 중단된 스레드가 정적 Thread.interrupted() 메서드를 호출하여 인터럽트 상태를 확인하면 인터럽트 상태가 재설정됩니다. 스레드가 다른 스레드의 인터럽트 상태를 확인하기 위해 사용하는 비정적 isInterrupted() 메서드는 인터럽트 플래그를 변경하지 않습니다. 일반적으로 InterruptedException을 발생시켜 종료되는 모든 메서드는 인터럽트 플래그를 재설정합니다. 그러나 다른 스레드가 인터럽트()를 호출하면 플래그가 즉시 다시 설정될 가능성이 항상 있습니다.
  39. 동기화된 블록에서 대기 및 알림 메소드가 호출되는 이유는 무엇입니까?

  40. 정적 블록이나 메소드에서 대기 및 알림을 호출하는 주된 이유는 Java API에서 이를 요구하기 때문입니다. 동기화된 블록 외부에서 호출하면 코드에서 IllegalMonitorStateException이 발생합니다. 더 영리한 이유는 대기 호출과 알림 호출 간의 경합 상태를 피하는 것입니다.
  41. 루프에서 대기 상태를 확인해야 하는 이유는 무엇입니까?

  42. 대기 중인 스레드가 루프에서 대기 상태를 확인하지 않으면 잘못된 경고 및 잘못된 깨우기 호출을 받을 가능성이 있으며 상태에 도달하지 않더라도 단순히 종료됩니다. 대기 중인 스레드가 깨어날 때 기다리고 있던 상태가 여전히 유효할 수 있다는 사실을 생각하지 않습니다. 실제로는 과거일 수도 있지만, inform() 메서드가 호출된 후 스레드가 깨어나기 전에 변경되었습니다. 따라서 루프 내에서 wait()를 호출하는 것이 항상 더 좋습니다.
  43. 동기화된 컬렉션과 동시 컬렉션의 차이점은 무엇입니까?

  44. 동기화된 컬렉션과 동시 컬렉션 모두 스레드로부터 안전한 컬렉션을 제공하지만 후자가 더 확장 가능합니다. Java 1.5 이전에는 프로그래머가 동기화된 컬렉션에만 액세스할 수 있었는데, 이는 여러 스레드가 동시에 액세스할 때 경합의 원인이 되어 시스템 확장을 어렵게 만들었습니다. Java 5에서는 스레드 안전성을 제공할 뿐만 아니라 잠금 제거 및 내부 테이블 분할과 같은 최신 기술을 사용하여 확장성을 향상시키는 ConcurrentHashMap과 같은 동시 컬렉션을 도입했습니다.
  45. 스택과 힙의 차이점은 무엇입니까?

  46. 멀티스레딩에 대한 질문에 이 질문이 나타나는 이유는 무엇입니까? 스택은 스레드와 밀접하게 연관된 메모리 조각이기 때문입니다. 각 스레드에는 지역 변수, 메서드 매개변수 및 호출 스택을 저장하는 자체 스택이 있습니다. 한 스레드의 스택에 저장된 변수는 다른 스레드에 표시되지 않습니다. 반면, 힙은 모든 스레드가 공유하는 공통 메모리 영역입니다. 로컬 수준이든 다른 수준이든 관계없이 개체는 힙에 생성됩니다. 성능을 향상시키기 위해 스레드는 일반적으로 힙의 값을 스택에 캐시합니다. 여기서 휘발성 변수가 작동합니다. Volatile은 스레드에게 주 메모리에서 변수를 읽도록 지시합니다.
  47. 스레드 풀이란 무엇입니까?

  48. 스레드를 생성하는 것은 시간과 리소스 측면에서 비용이 많이 듭니다. 요청이 처리되는 동안 스레드를 생성하면 응답 시간이 느려지고 프로세스는 제한된 수의 스레드만 생성할 수 있습니다. 이러한 문제를 방지하기 위해 애플리케이션 시작 시 스레드 풀이 생성되고 스레드는 요청을 처리하는 데 재사용됩니다. 이 스레드 풀을 "스레드 풀"이라고 하며, 그 안에 있는 스레드를 작업자 스레드라고 합니다. Java 1.5부터 Java API는 단위 시간당 하나의 작업만 처리하는 단일 스레드 풀, 고정 스레드 풀, 고정 개수의 풀 등 다양한 스레드 풀을 생성할 수 있는 Executor 프레임워크를 제공합니다. 스레드, 캐시된 스레드 풀, 확장 가능한 풀로 단기 작업이 많은 애플리케이션에 적합합니다.
  49. 생산자 소비자 문제를 해결하는 방법은 무엇입니까?

  50. 실제로 해결하는 대부분의 스레드 문제는 한 스레드가 문제를 생성하고 두 번째 스레드가 문제를 소비하는 생산자 소비자 패턴에서 비롯됩니다. 이 문제를 해결하려면 내부 스레드 상호 작용을 구축하는 방법을 알아야 합니다. 낮은 수준에서는 대기 및 알림 메서드를 활용할 수 있고, 높은 수준에서는 Semaphore 또는 BlockingQueue를 활용할 수 있습니다.
  51. 교착상태를 피하는 방법은 무엇입니까?

  52. 번역: 스레드별 상위 50개 인터뷰 질문.  1부. - 1 교착 상태는 스레드가 두 번째 스레드가 어떤 작업을 수행하기를 기다리고 있고, 두 번째 스레드도 동시에 첫 번째 스레드와 동일한 작업을 기다리는 상태입니다. 이는 프로그램이 정지되어 의도한 대로 작동하지 않게 만드는 매우 심각한 문제입니다. 교착 상태는 다음 4가지 상태에 도달할 때 발생합니다.
    • 상호배제: 분할 불가 ​​모드에서는 최소한 하나의 자원을 점유해야 합니다. 주어진 시간에 하나의 프로세스만 리소스를 사용할 수 있습니다.
    • 보류 및 대기: 프로세스는 최소한 하나의 리소스를 보유하고 다른 프로세스가 보유한 추가 리소스를 요청합니다.
    • 사전 정리 없음: 운영 체제는 리소스가 이미 점유된 경우 리소스를 재할당하지 않으며 보류 프로세스에 자발적으로 제공되어야 합니다.
    • 순환 대기(Cyclic wait): 프로세스는 다른 프로세스가 리소스를 해제할 때까지 기다리고, 해당 프로세스는 첫 번째 프로세스가 리소스를 해제할 때까지 기다립니다.
    교착 상태를 피하는 가장 간단한 방법은 루프에서 기다리는 것을 피하는 것입니다. 이는 특정 순서로 잠금을 획득하고 반대 순서로 해제함으로써 달성할 수 있습니다.
  53. 라이브락과 교착상태의 차이점은 무엇인가요?

  54. 라이브록은 교착 상태와 유사합니다. 라이브록에서만 관련 스레드 또는 프로세스의 상태가 서로에 따라 지속적으로 변경됩니다. Livelock은 자원 부족의 특별한 경우입니다. 라이브록의 실제 예는 두 사람이 좁은 복도에서 만나 예의를 갖추려고 노력하면서 옆으로 물러서서 끝없이 좌우로 움직이는 것입니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION