CodeGym/Java Blog/무작위의/Java 개발자 직위에 대한 취업 면접의 질문과 답변을 살펴보세요. 12부
John Squirrels
레벨 41
San Francisco

Java 개발자 직위에 대한 취업 면접의 질문과 답변을 살펴보세요. 12부

무작위의 그룹에 게시되었습니다
회원
안녕! 아는 것이 힘이다. 첫 번째 인터뷰에서 더 많은 지식을 가질수록 자신감이 더 커질 것입니다. Java 개발자 직위에 대한 취업 면접의 질문과 답변을 살펴보세요.  파트 12 - 1당신이 지식으로 가득 찬 큰 두뇌를 가지고 오면 면접관은 당신을 혼란스럽게 하기 어렵고 유쾌하게 놀라게 될 것입니다. 따라서 더 이상 고민하지 않고 오늘 우리는 Java 개발자를 위한 질문을 검토하여 이론적 기반을 계속 강화할 것입니다.

103. 상속 중 예외 검사에는 어떤 규칙이 적용됩니까?

질문을 올바르게 이해하면 상속 중 예외 작업 규칙에 대해 묻는 것입니다. 관련 규칙은 다음과 같습니다.
  • 하위 항목/구현에서 재정의되거나 구현된 메서드는 슈퍼클래스/인터페이스 메서드의 예외보다 계층 구조에서 더 높은 확인된 예외를 발생시킬 수 없습니다.
예를 들어, IOException을 발생시키는 메소드가 있는 Animal 인터페이스가 있다고 가정해 보겠습니다 .
public interface Animal {
   void speak() throws IOException;
}
이 인터페이스를 구현할 때 더 일반적인 발생 가능한 예외(예: Exception , Throwable )를 노출할 수는 없지만 기존 예외를 FileNotFoundException 과 같은 하위 클래스로 대체할 수 있습니다 .
public class Cat implements Animal {
   @Override
   public void speak() throws FileNotFoundException {
// Some implementation
   }
}
  • 하위 클래스 생성자의 throws 절 에는 객체를 생성하기 위해 호출된 슈퍼클래스 생성자에서 발생한 모든 예외 클래스가 포함되어야 합니다.
Animal 클래스 의 생성자가 많은 예외를 발생시킨다고 가정해 보겠습니다.
public class Animal {
  public Animal() throws ArithmeticException, NullPointerException, IOException {
  }
그런 다음 하위 클래스 생성자도 이를 발생시켜야 합니다.
public class Cat extends Animal {
   public Cat() throws ArithmeticException, NullPointerException, IOException {
       super();
   }
또는 메서드와 마찬가지로 좀 더 일반적인 예외를 지정할 수 있습니다. 우리의 경우 Exception 을 표시할 수 있습니다 . 왜냐하면 Exception은 더 일반적이고 슈퍼클래스에 표시된 세 가지 예외 모두의 공통 조상이기 때문입니다.
public class Cat extends Animal {
   public Cat() throws Exception {
       super();
   }

104. finally 블록이 실행되지 않는 코드를 작성할 수 있습니까?

먼저 마지막 이 무엇인지 기억해 봅시다 . 앞서 우리는 예외 포착 메커니즘을 조사했습니다. try 블록은 예외가 포착될 위치를 지정하고, catch 블록은 해당 예외가 포착될 때 호출될 코드입니다. finally 키워드 로 표시된 세 번째 코드 블록은 catch 블록을 대체하거나 뒤에 올 수 있습니다. 이 블록의 기본 개념은 try 또는 catch 블록에서 발생하는 상황에 관계없이(예외 발생 여부에 관계없이) 해당 코드가 항상 실행된다는 것입니다 . 이 블록이 실행되지 않는 인스턴스는 드물고 비정상입니다. 가장 간단한 예는 finally 블록 이전에 System.exit(0)이 호출되어 프로그램이 종료되는 경우입니다.
try {
   throw new IOException();
} catch (IOException e) {
   System.exit(0);
} finally {
   System.out.println("This message will not be printed on the console");
}
finally 블록이 실행되지 않는 다른 상황도 있습니다 :
  • 예를 들어 심각한 시스템 오류로 인해 발생한 비정상적인 프로그램 종료 또는 애플리케이션 충돌을 일으키는 일부 오류(예: 애플리케이션 스택이 오버플로될 때 발생하는 StackOverflowError )입니다.

  • 또 다른 상황은 데몬 스레드가 try-finally 블록 에 진입했지만 프로그램의 메인 스레드가 종료되는 경우입니다. 결국 데몬 스레드는 우선순위가 높지 않거나 필수가 아닌 백그라운드 작업을 위한 것이므로 애플리케이션은 작업이 완료될 때까지 기다리지 않습니다.

  • 가장 무의미한 예는 try 또는 catch 블록 내부의 무한 루프입니다 . 일단 내부에 들어가면 스레드가 영원히 거기에 갇히게 됩니다.

    try {
       while (true) {
       }
    } finally {
       System.out.println("This message will not be printed on the console");
    }
이 질문은 주니어 개발자 인터뷰에서 매우 인기가 있으므로 이러한 예외적인 상황 몇 가지를 기억하는 것이 좋습니다. Java 개발자 직위에 대한 취업 면접의 질문과 답변을 살펴보세요.  파트 12 - 2

105. 단일 catch 블록에서 여러 예외를 처리하는 예제를 작성하세요.

1) 이 질문이 올바르게 요청되었는지 확실하지 않습니다. 내가 아는 한, 이 질문은 여러 catch 블록과 단일 try를 참조하고 있습니다 .
try {
  throw new FileNotFoundException();
} catch (FileNotFoundException e) {
   System.out.print("Oops! There was an exception: " + e);
} catch (IOException e) {
   System.out.print("Oops! There was an exception: " + e);
} catch (Exception e) {
   System.out.print("Oops! There was an exception: " + e);
}
try 블록 에서 예외가 발생하면 연결된 catch 블록은 위에서 아래로 순차적으로 예외를 잡으려고 시도합니다. 예외가 catch 블록 중 하나와 일치하면 나머지 블록은 더 이상 이를 catch하고 처리할 수 없습니다. 이는 모두 catch 블록 세트에서 더 좁은 예외가 더 일반적인 예외 위에 배열된다는 것을 의미합니다 . 예를 들어 첫 번째 catch 블록이 Exception 클래스를 포착하면 후속 블록은 확인된 예외를 포착하지 않습니다. 즉, Exception 하위 클래스가 있는 나머지 블록은 완전히 쓸모가 없습니다. 2) 아니면 질문이 올바르게 요청되었을 수도 있습니다. 이 경우 다음과 같이 예외를 처리할 수 있습니다.
try {
  throw new NullPointerException();
} catch (Exception e) {
   if (e instanceof FileNotFoundException) {
       // Some handling that involves a narrowing type conversion: (FileNotFoundException)e
   } else if (e instanceof ArithmeticException) {
       // Some handling that involves a narrowing type conversion: (ArithmeticException)e
   } else if(e instanceof NullPointerException) {
       // Some handling that involves a narrowing type conversion: (NullPointerException)e
   }
예외를 잡기 위해 catch를 사용한 후 , 객체가 특정 유형에 속하는지 확인하는 instanceof 연산자 를 사용하여 특정 유형을 찾으려고 합니다 . 이를 통해 부정적인 결과에 대한 두려움 없이 자신있게 축소 유형 변환을 수행할 수 있습니다. 동일한 상황에서 두 가지 접근 방식 중 하나를 적용할 수 있습니다. 나는 두 번째 옵션을 좋은 접근 방식이라고 부르지 않기 때문에 질문에 대해 의구심을 표명했습니다. 내 경험상 한번도 본 적이 없으며 여러 catch 블록을 포함하는 첫 번째 접근 방식이 널리 퍼져 있습니다.

106. 예외를 강제로 발생시킬 수 있는 연산자는 무엇입니까? 예시 작성

위의 예에서 이미 여러 번 사용했지만 다시 한 번 반복하겠습니다. 바로 throw 키워드입니다. 수동으로 예외를 발생시키는 예:
throw new NullPointerException();

107. 메인 메소드가 예외를 던질 수 있나요? 그렇다면 어디로 가는 걸까요?

우선, 주요 메소드는 일반적인 메소드에 지나지 않는다는 점을 지적하고 싶습니다. 예, 프로그램 실행을 시작하기 위해 가상 머신에서 호출하지만 그 이상으로 다른 코드에서도 호출할 수 있습니다. 즉, throws 키워드 뒤에 확인된 예외를 표시하는 것과 관련된 일반적인 규칙도 적용됩니다 .
public static void main(String[] args) throws IOException {
따라서 예외가 발생할 수 있습니다. main이 프로그램의 시작점으로 호출 되면 (다른 방법이 아닌), 발생하는 모든 예외는 UncaughtExceptionHandler 에 의해 처리됩니다 . 각 스레드에는 하나의 핸들러가 있습니다(즉, 각 스레드에 하나의 핸들러가 있습니다). 필요한 경우 자신만의 핸들러를 생성하고 public static void main(String[] args) throws IOException {setDefaultUncaughtExceptionHandler 메서드를 public static void main(String[] args) throws IOException {Thread 객체에서 호출하여 설정할 수 있습니다.

멀티스레딩

Java 개발자 직위에 대한 취업 면접의 질문과 답변을 살펴보세요.  파트 12 - 3

108. 멀티스레드 환경에서 작업하기 위한 어떤 메커니즘을 알고 있습니까?

Java의 멀티스레딩에 대한 기본 메커니즘은 다음과 같습니다.
  • 동기화 키워드는 스레드가 진입할 때 메소드/블록을 잠그고 다른 스레드가 진입하는 것을 방지하는 방법입니다.

  • 휘발성 키워드 는 다른 스레드에서 액세스하는 변수에 대한 일관된 액세스를 보장합니다. 즉, 이 수정자를 변수에 적용하면 해당 변수를 할당하고 읽는 모든 작업이 원자성이 됩니다. 즉, 스레드는 변수를 로컬 메모리에 복사하여 변경하지 않습니다. 원래 값이 변경됩니다.

  • Runnable — 일부 클래스에서 이 인터페이스(단일 run() 메서드 로 구성됨 )를 구현할 수 있습니다.

    public class CustomRunnable implements Runnable {
       @Override
       public void run() {
           // Some logic
       }
    }

    해당 클래스의 객체를 생성하면 객체를 Thread 생성자에 전달한 다음 start() 메서드 를 호출하여 새 스레드를 시작할 수 있습니다 .

    Runnable runnable = new CustomRunnable();
    new Thread(runnable).start();

    start 메소드는 별도의 스레드에서 구현된 run() 메소드를 실행 합니다 .

  • Thread — 이 클래스를 상속하고 해당 run 메서드를 재정의할 수 있습니다.

    public class CustomThread extends Thread {
       @Override
       public void run() {
           // Some logic
       }
    }

    이 클래스의 객체를 생성한 다음 start() 메서드를 호출하여 새 스레드를 시작할 수 있습니다.

    new CustomThread().start();

  • 동시성 — 다중 스레드 환경에서 작업하기 위한 도구 패키지입니다.

    그것은 다음으로 구성됩니다:

    • 동시 컬렉션 — 이는 다중 스레드 환경에서 작업하기 위해 명시적으로 생성된 컬렉션 컬렉션입니다.

    • 대기열 — 다중 스레드 환경(차단 및 비차단)을 위한 특수 대기열입니다.

    • 동기화 장치 — 다중 스레드 환경에서 작업하기 위한 특수 유틸리티입니다.

    • 실행자 — 스레드 풀을 생성하는 메커니즘입니다.

    • 잠금 — 표준 동기화 메커니즘(synchronized, wait, inform, informAll)보다 더 유연한 스레드 동기화 메커니즘입니다.

    • Atomics — 멀티스레딩에 최적화된 클래스입니다. 각 작업은 원자적입니다.

109. 스레드 간 동기화에 대해 알려주세요. wait(), inform(), informAll() 및 Join() 메소드는 무엇입니까?

스레드 간 동기화는 동기화된 키워드에 관한 것입니다. 이 수정자는 블록에 직접 배치할 수 있습니다.
synchronized (Main.class) {
   // Some logic
}
또는 메소드 서명에서 직접:
public synchronized void move() {
   // Some logic }
앞서 말했듯 이 동기화는 한 스레드가 진입하면 블록/메서드를 다른 스레드에 잠그는 메커니즘입니다. 코드 블록/메서드를 방으로 생각해보자. 어떤 실이 방에 접근하여 들어가고 열쇠로 문을 잠급니다. 다른 스레드가 방에 접근하면 문이 잠겨 있는 것을 확인하고 방을 사용할 수 있을 때까지 근처에서 기다립니다. 첫 번째 스레드가 방에서의 업무를 마치면 문을 열고 방을 나가며 열쇠를 놓습니다. 제가 몇 번이나 열쇠에 대해 언급한 데에는 이유가 있습니다. 비슷한 것이 실제로 존재하기 때문입니다. 이는 통화 중/한가함 상태를 갖는 특수 개체입니다. Java의 모든 객체에는 이러한 객체가 있으므로 동기화된 블록을 사용할 때 괄호를 사용하여 뮤텍스가 잠길 객체를 나타내야 합니다.
Cat cat = new Cat();
synchronized (cat) {
   // Some logic
}
첫 번째 예제( Main.class ) 에서 했던 것처럼 클래스와 관련된 뮤텍스를 사용할 수도 있습니다 . 결국 메소드에서 동기화를 사용할 때 잠그려는 객체를 지정하지 않습니다. 그렇죠? 이 경우 비정적 메서드의 경우 잠길 뮤텍스는 this 개체, 즉 클래스의 현재 개체입니다. 정적 메서드의 경우 현재 클래스( this.getClass(); ) 와 연결된 뮤텍스가 잠겨 있습니다. wait()는 마치 현재 모니터(앵커와 같은 것)에 연결되는 것처럼 뮤텍스를 해제하고 현재 스레드를 대기 상태로 만드는 방법입니다. 이로 인해 이 메서드는 동기화된 블록이나 메서드에서만 호출될 수 있습니다. 그렇지 않으면 무엇을 기다리고 무엇을 출시할 것인가?). 또한 이는 Object 클래스 의 메서드라는 점에 유의하세요 . 글쎄, 하나가 아니라 세 개:
  • wait()는 다른 스레드가 이 객체에 대해 inform() 또는 informAll() 메서드 를 호출할 때까지 현재 스레드를 대기 상태로 전환합니다 (이러한 메서드에 대해서는 나중에 설명하겠습니다).

  • wait(long timeout)은 다른 스레드가 이 객체에 대해 inform() 또는 informAll() 메서드 를 호출하거나 timeout으로 지정된 시간 간격이 만료될 때까지 현재 스레드를 대기 상태로 전환합니다 .

  • wait(long timeout, int nanos)는 이전 방법과 비슷하지만 여기서 nanos를 사용하면 나노초(보다 ​​정확한 시간 제한)를 지정할 수 있습니다.

  • inform()을 사용 하면 현재 동기화 블록에서 대기 중인 임의의 스레드 하나를 깨울 수 있습니다. 다시 말하지만, 이 메서드는 동기화된 블록이나 메서드 에서만 호출할 수 있습니다 (결국 다른 곳에서는 깨어날 사람이 없습니다).

  • informAll()은 현재 모니터에서 대기 중인 모든 스레드를 깨웁니다( 동기화 블록이나 메소드에서만 사용됨).

110. 쓰레드를 어떻게 멈추나요?

여기서 가장 먼저 말해야 할 것은 run()이 완료될 때까지 스레드가 자동으로 종료된다는 것입니다. 그러나 때로는 메서드가 완료되기 전에 일정보다 먼저 스레드를 종료하고 싶을 때도 있습니다. 그럼 우리는 무엇을 합니까? Thread 객체 에 stop() 메소드를 사용할 수 있을까요 ? 아니요! 해당 방법은 더 이상 사용되지 않으며 시스템 충돌을 일으킬 수 있습니다. 그럼 어쩌지? 이를 수행하는 방법에는 두 가지가 있습니다. 먼저 내부 부울 플래그를 사용합니다. 예를 살펴보겠습니다. 스레드가 완전히 멈출 때까지 화면에 특정 문구를 표시하는 스레드를 구현했습니다. Java 개발자 직위에 대한 취업 면접의 질문과 답변을 살펴보세요.  파트 12 - 4
public class CustomThread extends Thread {
private boolean isActive;

   public CustomThread() {
       this.isActive = true;
   }

   @Override
   public void run() {
       {
           while (isActive) {
               System.out.println("The thread is executing some logic...");
           }
           System.out.println("The thread stopped!");
       }
   }

   public void stopRunningThread() {
       isActive = false;
   }
}
stopRunningThread() 메서드를 호출하면 내부 플래그가 false로 설정되어 run() 메서드가 종료됩니다. main 에서 호출해 봅시다 :
System.out.println("Program starting...");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// As long as our main thread is asleep, our CustomThread runs and prints its message on the console
thread.stopRunningThread();
System.out.println("Program stopping...");
결과적으로 콘솔에 다음과 같은 내용이 표시됩니다.
프로그램 시작 중... 스레드가 일부 논리를 실행 중입니다... 스레드가 일부 논리를 실행 중입니다... 스레드가 일부 논리를 실행 중입니다... 스레드가 일부 논리를 실행 중입니다... 스레드가 일부 논리를 실행 중입니다... 스레드가 일부 논리를 실행 중입니다... 프로그램 중지 중... 스레드가 중지되었습니다!
이는 스레드가 시작되고 콘솔에 여러 메시지가 인쇄된 다음 성공적으로 중지되었음을 의미합니다. 표시되는 메시지 수는 출시마다 다릅니다. 때로는 보조 스레드가 전혀 아무것도 표시하지 않을 수도 있습니다. 구체적인 동작은 메인 스레드가 휴면 상태에 있는 기간에 따라 달라집니다. 대기 시간이 길어질수록 보조 스레드가 아무 것도 표시하지 못할 가능성이 줄어듭니다. 1ms의 절전 시간을 사용하면 메시지를 거의 볼 수 없습니다. 그러나 20ms로 설정하면 거의 항상 메시지가 표시됩니다. 휴면 시간이 짧으면 스레드가 시작되어 작업을 수행할 시간이 없습니다. 대신 즉시 중지됩니다. 두 번째 방법은 Thread 객체 에 Interrupted() 메서드를 사용하는 것입니다 . 내부 중단 플래그의 값을 반환하며 기본적으로 false 입니다. 또는 이 플래그를 true 로 설정하는 Interrupt() 메서드 (플래그가 true 이면 스레드 실행이 중지되어야 함). 예를 살펴보겠습니다:
public class CustomThread extends Thread {

   @Override
   public void run() {
       {
           while (!Thread.interrupted()) {
               System.out.println("The thread is executing some logic...");
           }
           System.out.println("The thread stopped!");
       }
   }
}
메인 에서 실행 중 :
System.out.println("Program starting...");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Program stopping...");
이를 실행한 결과는 첫 번째 경우와 동일하지만 저는 이 접근 방식이 더 마음에 듭니다. 코드를 덜 작성하고 기성 표준 기능을 더 많이 사용했기 때문입니다. 자, 오늘은 여기까지입니다!
코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다