CodeGym/Java Blog/무작위의/Java Core에 대한 상위 50개의 면접 질문 및 답변. 2 부
John Squirrels
레벨 41
San Francisco

Java Core에 대한 상위 50개의 면접 질문 및 답변. 2 부

무작위의 그룹에 게시되었습니다
회원
Java Core에 대한 상위 50개의 면접 질문 및 답변. 1 부Java Core에 대한 상위 50개의 면접 질문 및 답변.  파트 2 - 1

멀티스레딩

24. Java에서 새 스레드를 어떻게 생성합니까?

어떤 식으로든 스레드는 Thread 클래스를 사용하여 생성됩니다. 하지만 이를 수행하는 다양한 방법이 있습니다…
  1. 상속 java.lang.Thread .
  2. java.lang.Runnable 인터페이스 구현 — Thread 클래스의 생성자는 Runnable 객체를 사용합니다.
그들 각각에 대해 이야기합시다.

Thread 클래스 상속

이 경우 클래스가 java.lang.Thread 를 상속하도록 합니다 . 여기에는 run() 메서드가 있으며 이것이 바로 우리에게 필요한 것입니다. 새 스레드의 모든 생명과 논리는 이 메서드에 있습니다. 새 스레드의 기본 메서드 와 비슷합니다 . 그 후에 남은 것은 우리 클래스의 객체를 생성하고 start() 메서드를 호출하는 것입니다. 그러면 새 스레드가 생성되고 해당 논리 실행이 시작됩니다. 한 번 보자:
/**
* An example of how to create threads by inheriting the {@link Thread} class.
*/
class ThreadInheritance extends Thread {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance threadInheritance1 = new ThreadInheritance();
       ThreadInheritance threadInheritance2 = new ThreadInheritance();
       ThreadInheritance threadInheritance3 = new ThreadInheritance();
       threadInheritance1.start();
       threadInheritance2.start();
       threadInheritance3.start();
   }
}
콘솔 출력은 다음과 같습니다.
스레드-1 스레드-0 스레드-2
즉, 여기에서도 스레드가 순서대로 실행되는 것이 아니라 JVM이 스레드를 실행하는 데 적합하다고 판단하는 대로 실행되는 것을 볼 수 있습니다. :)

Runnable 인터페이스 구현

상속에 반대하거나 이미 다른 클래스를 상속받은 경우 java.lang.Runnable 인터페이스를 사용할 수 있습니다. 여기서 우리는 위의 예에서와 같이 run() 메서드 를 구현하여 클래스가 이 인터페이스를 구현하도록 합니다 . 남은 것은 Thread 개체를 만드는 것입니다. 더 많은 코드 라인이 더 나쁜 것처럼 보일 것입니다. 그러나 우리는 상속이 얼마나 해로운지, 그리고 그것을 피하는 것이 더 낫다는 것을 알고 있습니다 ;) 살펴보세요:
/**
* An example of how to create threads from the {@link Runnable} interface.
* It's easier than easy — we implement this interface and then pass an instance of our object
* to the constructor.
*/
class ThreadInheritance implements Runnable {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance runnable1 = new ThreadInheritance();
       ThreadInheritance runnable2 = new ThreadInheritance();
       ThreadInheritance runnable3 = new ThreadInheritance();

       Thread threadRunnable1 = new Thread(runnable1);
       Thread threadRunnable2 = new Thread(runnable2);
       Thread threadRunnable3 = new Thread(runnable3);

       threadRunnable1.start();
       threadRunnable2.start();
       threadRunnable3.start();
   }
}
결과는 다음과 같습니다.
스레드-0 스레드-1 스레드-2

25. 프로세스와 스레드의 차이점은 무엇입니까?

Java Core에 대한 상위 50개의 면접 질문 및 답변.  파트 2 - 2프로세스와 스레드는 다음과 같은 점에서 다릅니다.
  1. 실행 중인 프로그램을 프로세스라고 하지만 스레드는 프로세스의 일부입니다.
  2. 프로세스는 독립적이지만 스레드는 프로세스의 일부입니다.
  3. 프로세스는 메모리에서 서로 다른 주소 공간을 갖지만 스레드는 공통 주소 공간을 공유합니다.
  4. 스레드 간 컨텍스트 전환은 프로세스 간 전환보다 빠릅니다.
  5. 프로세스 간 통신은 스레드 간 통신보다 느리고 비용이 많이 듭니다.
  6. 상위 프로세스의 변경 사항은 하위 프로세스에 영향을 미치지 않지만 상위 스레드의 변경 사항은 하위 스레드에 영향을 줄 수 있습니다.

26. 멀티스레딩의 이점은 무엇입니까?

  1. 다중 스레딩을 사용하면 응용 프로그램/프로그램이 이미 일부 백그라운드 작업을 실행 중인 경우에도 항상 입력에 응답할 수 있습니다.
  2. 멀티스레딩을 사용하면 스레드가 독립적으로 실행되기 때문에 작업을 더 빠르게 완료할 수 있습니다.
  3. 멀티스레딩은 스레드가 공유 메모리 리소스에 액세스할 수 있기 때문에 캐시 메모리를 더 잘 사용합니다.
  4. 멀티스레딩은 하나의 서버가 여러 스레드를 동시에 실행할 수 있기 때문에 필요한 서버 수를 줄입니다.

27. 스레드의 수명 주기에서 상태는 무엇입니까?

Java Core에 대한 상위 50개의 면접 질문 및 답변.  파트 2 - 3
  1. New: 이 상태에서 Thread 객체는 new 연산자를 사용하여 생성되지만 아직 새로운 스레드가 존재하지 않습니다. 스레드는 start() 메서드를 호출할 때까지 시작되지 않습니다.
  2. Runnable: 이 상태에서 스레드는 start() 이후에 실행할 준비가 됩니다. 메서드가 호출됩니다. 그러나 아직 스레드 스케줄러에 의해 선택되지 않았습니다.
  3. Running: 이 상태에서 스레드 스케줄러는 준비 상태에서 스레드를 선택하고 실행합니다.
  4. Waiting/Blocked: 이 상태에서는 스레드가 실행되지 않지만 여전히 활성 상태이거나 다른 스레드가 완료되기를 기다리고 있습니다.
  5. Dead/Terminated: 스레드가 run() 메서드를 종료하면 죽은 상태 또는 종료된 상태입니다.

28. 스레드를 두 번 실행할 수 있습니까?

아니요, 스레드를 다시 시작할 수 없습니다. 스레드가 시작되고 실행된 후에 Dead 상태가 되기 때문입니다. 스레드를 두 번 시작하려고 하면 java.lang.IllegalThreadStateException 이 발생합니다. 한 번 보자:
class DoubleStartThreadExample extends Thread {

   /**
    * Simulate the work of a thread
    */
   public void run() {
	// Something happens. At this state, this is not essential.
   }

   /**
    * Start the thread twice
    */
   public static void main(String[] args) {
       DoubleStartThreadExample doubleStartThreadExample = new DoubleStartThreadExample();
       doubleStartThreadExample.start();
       doubleStartThreadExample.start();
   }
}
실행이 동일한 스레드의 두 번째 시작에 도달하는 즉시 예외가 발생합니다. 직접 해보세요 ;) 백 번 듣는 것보다 한 번 보시는 게 낫습니다.

29. start()를 호출하지 않고 직접 run()을 호출하면 어떻게 됩니까?

예, 확실히 run() 메서드를 호출할 수 있지만 새 스레드가 생성되지 않고 해당 메서드가 별도의 스레드에서 실행되지 않습니다. 이 경우 일반 메서드를 호출하는 일반 개체가 있습니다. start() 메소드 에 대해 이야기하고 있다면 그것은 또 다른 문제입니다. 이 메서드가 호출되면 JVM 이 새 스레드를 시작합니다. 이 스레드는 차례로 우리 메서드를 호출합니다. ;) 믿을 수 없나요? 여기에서 시도해 보세요.
class ThreadCallRunExample extends Thread {

   public void run() {
       for (int i = 0; i < 5; i++) {
           System.out.print(i);
       }
   }

   public static void main(String args[]) {
       ThreadCallRunExample runExample1 = new ThreadCallRunExample();
       ThreadCallRunExample runExample2 = new ThreadCallRunExample();

       // Two ordinary methods will be called in the main thread, one after the other.
       runExample1.run();
       runExample2.run();
   }
}
콘솔 출력은 다음과 같습니다.
0123401234
보시다시피 스레드가 생성되지 않았습니다. 모든 것이 일반 수업과 동일하게 작동했습니다. 먼저 첫 번째 개체의 메서드가 실행된 다음 두 번째 개체의 메서드가 실행되었습니다.

30. 데몬 스레드란 무엇입니까?

데몬 스레드는 다른 스레드보다 우선 순위가 낮은 작업을 수행하는 스레드입니다. 즉, 다른 (메인) 스레드와 함께 수행해야 하는 보조 작업을 수행하는 것입니다. 가비지 수집, 종료자 등과 같이 자동으로 실행되는 많은 데몬 스레드가 있습니다.

Java가 데몬 스레드를 종료하는 이유는 무엇입니까?

데몬 스레드의 유일한 목적은 사용자 스레드에 백그라운드 지원을 제공하는 것입니다. 따라서 메인 스레드가 종료되면 JVM은 모든 데몬 스레드를 자동으로 종료합니다.

스레드 클래스의 메서드

java.lang.Thread 클래스는 데몬 스레드 작업을 위한 두 가지 방법을 제공합니다 .
  1. public void setDaemon(boolean status) — 이 메서드는 데몬 스레드가 될지 여부를 나타냅니다. 기본값은 false 입니다 . 즉, 특별히 지정하지 않는 한 데몬 스레드가 생성되지 않습니다.
  2. public boolean isDaemon() — 이 메서드는 기본적으로 이전 메서드를 사용하여 설정한 daemon 변수 에 대한 getter입니다 .
예:
class DaemonThreadExample extends Thread {

   public void run() {
       // Checks whether this thread is a daemon
       if (Thread.currentThread().isDaemon()) {
           System.out.println("daemon thread");
       } else {
           System.out.println("user thread");
       }
   }

   public static void main(String[] args) {
       DaemonThreadExample thread1 = new DaemonThreadExample();
       DaemonThreadExample thread2 = new DaemonThreadExample();
       DaemonThreadExample thread3 = new DaemonThreadExample();

       // Make thread1 a daemon thread.
       thread1.setDaemon(true);

       System.out.println("daemon? " + thread1.isDaemon());
       System.out.println("daemon? " + thread2.isDaemon());
       System.out.println("daemon? " + thread3.isDaemon());

       thread1.start();
       thread2.start();
       thread3.start();
   }
}
콘솔 출력:
악마? 진정한 데몬? 거짓 데몬? 거짓 데몬 스레드 사용자 스레드 사용자 스레드
출력에서 스레드 자체 내부에서 정적 currentThread() 메서드를 사용하여 스레드를 찾을 수 있음을 알 수 있습니다. 또는 스레드 개체에 대한 참조가 있는 경우 해당 개체에서 직접 찾을 수도 있습니다. 이는 필요한 수준의 구성 가능성을 제공합니다.

31. 스레드가 생성된 후 데몬으로 만들 수 있습니까?

아니요. 이 작업을 시도하면 IllegalThreadStateException 이 발생합니다 . 이는 데몬 스레드가 시작되기 전에만 생성할 수 있음을 의미합니다. 예:
class SetDaemonAfterStartExample extends Thread {

   public void run() {
       System.out.println("Working...");
   }

   public static void main(String[] args) {
       SetDaemonAfterStartExample afterStartExample = new SetDaemonAfterStartExample();
       afterStartExample.start();

       // An exception will be thrown here
       afterStartExample.setDaemon(true);
   }
}
콘솔 출력:
작업중... 예외가 "main" 스레드 java.lang.IllegalThreadStateException at java.lang.Thread.setDaemon(Thread.java:1359) at SetDaemonAfterStartExample.main(SetDaemonAfterStartExample.java:14)

32. 종료 후크란 무엇입니까?

종료 후크는 JVM(Java Virtual Machine)이 종료되기 전에 암시적으로 호출되는 스레드입니다. 따라서 JVM(Java Virtual Machine)이 정상적으로 종료되거나 비정상적으로 종료될 때 리소스를 해제하거나 상태를 저장하는 데 사용할 수 있습니다. 다음 방법을 사용하여 종료 후크를 추가할 수 있습니다 .
Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
예에 표시된 대로:
/**
* A program that shows how to start a shutdown hook thread,
* which will be executed right before the JVM shuts down
*/
class ShutdownHookThreadExample extends Thread {

   public void run() {
       System.out.println("shutdown hook executed");
   }

   public static void main(String[] args) {

       Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());

       System.out.println("Now the program is going to fall asleep. Press Ctrl+C to terminate it.");
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
콘솔 출력:
이제 프로그램이 잠들 것입니다. Ctrl+C를 눌러 종료합니다. 종료 후크 실행

33. 동기화란 무엇입니까?

Java에서 동기화는 모든 공유 리소스에 대한 여러 스레드의 액세스를 제어하는 ​​기능입니다. 여러 스레드가 동일한 작업을 동시에 수행하려고 하면 잘못된 결과를 얻을 수 있습니다. 이 문제를 해결하기 위해 Java는 한 번에 하나의 스레드만 실행할 수 있도록 하는 동기화를 사용합니다. 동기화는 세 가지 방법으로 달성할 수 있습니다.
  • 메서드 동기화
  • 특정 블록 동기화
  • 정적 동기화

메서드 동기화

동기화된 메서드는 모든 공유 리소스에 대한 개체를 잠그는 데 사용됩니다. 스레드가 동기화된 메서드를 호출하면 개체의 잠금을 자동으로 획득하고 스레드가 작업을 완료하면 잠금을 해제합니다. 이 작업을 수행하려면 동기화된 키워드를 추가해야 합니다 . 예제를 보면 이것이 어떻게 작동하는지 확인할 수 있습니다.
/**
* An example where we synchronize a method. That is, we add the synchronized keyword to it.
* There are two authors who want to use one printer. Each of them has composed their own poems
* And of course they don’t want their poems mixed up. Instead, they want work to be performed in * * * order for each of them
*/
class Printer {

   synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer  = new Printer();

       // Create two threads
       Writer1 writer1 = new Writer1(printer);
       Writer2 writer2 = new Writer2(printer);

       // Start them
       writer1.start();
       writer2.start();
   }
}

/**
* Author No. 1, who writes an original poem.
*/
class Writer1 extends Thread {
   Printer printer;

   Writer1(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<string> poem = Arrays.asList("I ", this.getName(), " Write", " A Letter");
       printer.print(poem);
   }

}

/**
* Author No. 2, who writes an original poem.
*/
class Writer2 extends Thread {
   Printer printer;

   Writer2(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<String> poem = Arrays.asList("I Do Not ", this.getName(), " Not Write", " No Letter");
       printer.print(poem);
   }
}
콘솔 출력은 다음과 같습니다.
I Thread-0 편지 쓰기 I Don Not Thread-1 안 쓰기 편지 없음

동기화 블록

동기화된 블록은 메서드의 특정 리소스에서 동기화를 수행하는 데 사용할 수 있습니다. 대규모 메서드에서(예, 작성하면 안 되지만 가끔 발생하기도 함) 어떤 이유로 작은 섹션만 동기화해야 한다고 가정해 보겠습니다. 메서드의 코드를 모두 synchronized 블록에 넣으면 동기화된 메서드와 동일하게 작동합니다. 구문은 다음과 같습니다.
synchronized ("object to be locked") {
   // The code that must be protected
}
이전 예제를 반복하지 않기 위해 익명 클래스를 사용하여 스레드를 생성합니다. 즉 Runnable 인터페이스를 즉시 구현합니다.
/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   void print(List<String> wordsToPrint) {
       synchronized (this) {
           wordsToPrint.forEach(System.out::print);
       }
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer = new Printer();

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}

}
콘솔 출력은 다음과 같습니다.
나는 작가1 편지를 쓴다 I 안 쓴다2 편지를 쓰지 않는다

정적 동기화

정적 메서드를 동기화하면 개체가 아닌 클래스에서 잠금이 발생합니다. 이 예제에서는 동기화된 키워드를 정적 메서드에 적용하여 정적 동기화를 수행합니다.
/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   static synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               Printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               Printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}
콘솔 출력은 다음과 같습니다.
나는 글을 쓰지 않는다2 편지를 쓰지 않는다 I 작가1 편지를 쓴다

34. 휘발성 변수란 무엇입니까?

다중 스레드 프로그래밍에서 volatile 키워드는 스레드 안전을 위해 사용됩니다. 변경 가능한 변수가 수정되면 다른 모든 스레드에서 변경 사항을 볼 수 있으므로 한 번에 하나의 스레드에서 변수를 사용할 수 있습니다. volatile 키워드를 사용하면 변수가 스레드로부터 안전하고 공유 메모리에 저장되며 스레드가 해당 변수를 캐시에 저장하지 않는다는 것을 보장할 수 있습니다. 이것은 어떻게 생겼습니까?
private volatile AtomicInteger count;
변수에 휘발성을 추가하기만 하면 됩니다 . 그러나 이것이 완전한 스레드 안전을 의미하지는 않는다는 점을 명심하십시오. 결국 변수에 대한 작업은 원자적이지 않을 수 있습니다. 즉, 작업을 원자적으로, 즉 단일 CPU 명령으로 수행하는 Atomic 클래스를 사용할 수 있습니다. java.util.concurrent.atomic 패키지 에는 그러한 클래스가 많이 있습니다 .

35. 교착상태란?

Java에서 교착 상태는 멀티스레딩의 일부로 발생할 수 있는 것입니다. 스레드가 다른 스레드가 획득한 개체의 잠금을 기다리고 있고 두 번째 스레드는 첫 번째 스레드가 획득한 개체의 잠금을 기다리고 있을 때 교착 상태가 발생할 수 있습니다. 이는 두 스레드가 서로를 기다리고 있으며 코드 실행을 계속할 수 없음을 의미합니다. Java Core에 대한 상위 50개의 면접 질문 및 답변.  파트 2 - 4Runnable을 구현하는 클래스가 있는 예제를 살펴보겠습니다. 해당 생성자는 두 개의 리소스를 사용합니다. run() 메서드는 순서대로 잠금을 획득합니다. 이 클래스의 두 개체를 만들고 리소스를 다른 순서로 전달하면 쉽게 교착 상태에 빠질 수 있습니다.
class DeadLock {

   public static void main(String[] args) {
       final Integer r1 = 10;
       final Integer r2 = 15;

       DeadlockThread threadR1R2 = new DeadlockThread(r1, r2);
       DeadlockThread threadR2R1 = new DeadlockThread(r2, r1);

       new Thread(threadR1R2).start();
       new Thread(threadR2R1).start();
   }
}

/**
* A class that accepts two resources.
*/
class DeadlockThread implements Runnable {

   private final Integer r1;
   private final Integer r2;

   public DeadlockThread(Integer r1, Integer r2) {
       this.r1 = r1;
       this.r2 = r2;
   }

   @Override
   public void run() {
       synchronized (r1) {
           System.out.println(Thread.currentThread().getName() + " acquired resource: " + r1);

           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           synchronized (r2) {
               System.out.println(Thread.currentThread().getName() + " acquired resource: " + r2);
           }
       }
   }
}
콘솔 출력:
첫 번째 스레드가 첫 번째 리소스를 획득했습니다. 두 번째 스레드가 두 번째 리소스를 획득했습니다.

36. 교착 상태를 피하는 방법은 무엇입니까?

교착 상태가 어떻게 발생하는지 알기 때문에 몇 가지 결론을 도출할 수 있습니다.
  • 위의 예에서 교착 상태는 중첩 잠금이 있기 때문에 발생합니다. 즉, 동기화된 블록 안에 동기화된 블록이 있습니다. 이를 방지하려면 중첩 대신 새로운 상위 추상화 계층을 생성하고 동기화를 상위 수준으로 이동하고 중첩 잠금을 제거해야 합니다.
  • 더 많은 잠금을 수행할수록 교착 상태가 발생할 가능성이 높아집니다. 따라서 동기화된 블록을 추가할 때마다 정말 필요한지, 새 블록을 추가하지 않아도 되는지를 생각해야 합니다.
  • Thread.join() 사용 . 한 스레드가 다른 스레드를 기다리는 동안 교착 상태에 빠질 수도 있습니다. 이 문제를 방지하기 위해 join() 메서드 에 대한 시간 초과 설정을 고려할 수 있습니다 .
  • 스레드가 하나이면 교착 상태가 발생하지 않습니다. ;)

37. 경쟁 조건이란 무엇입니까?

실제 레이스에 자동차가 포함된다면 멀티스레딩 레이스에는 스레드가 포함됩니다. 하지만 왜? :/ 동일한 개체에 액세스할 수 있는 두 개의 스레드가 실행 중입니다. 그리고 동시에 공유 개체의 상태를 업데이트하려고 시도할 수 있습니다. 지금까지 모든 것이 명확합니다. 스레드는 문자 그대로 병렬로(프로세서에 둘 이상의 코어가 있는 경우) 또는 프로세서가 인터리브된 시간 조각을 할당하여 순차적으로 실행됩니다. 우리는 이러한 프로세스를 관리할 수 없습니다. 즉, 한 스레드가 개체에서 데이터를 읽을 때 다른 스레드가 개체를 변경하기 전에 개체를 변경할 시간이 있다고 보장할 수 없습니다. 이러한 문제는 이러한 "확인 및 조치" 콤보가 있을 때 발생합니다. 그게 무슨 뜻이야? 본문이 if 조건 자체를 변경하는 if 문 이 있다고 가정합니다 . 예를 들면 다음과 같습니다.
int z = 0;

// Check
if (z < 5) {
// Act
   z = z + 5;
}
z가 여전히 0일 때 두 스레드가 이 코드 블록에 동시에 들어갈 수 있으며 두 스레드 모두 값을 변경할 수 있습니다. 결과적으로 우리는 기대값 5를 얻지 못하고 대신 10을 얻습니다. 이것을 어떻게 피합니까? 확인하고 조치하기 전에 잠금을 획득한 다음 잠금을 해제해야 합니다. 즉, 첫 번째 스레드가 if 블록에 들어가 모든 작업을 수행하고 z 를 변경 한 다음에만 다음 스레드에게 동일한 작업을 수행할 기회를 제공해야 합니다. 그러나 다음 스레드는 z가 이제 5이므로 if 블록 에 들어가지 않습니다.
// Acquire the lock for z
if (z < 5) {
   z = z + 5;
}
// Release z's lock
===================================================

결론 대신

끝까지 읽어주신 모든 분들께 감사하다는 말씀을 드리고 싶습니다. 먼 길이었지만 참았어! 모든 것이 명확하지 않을 수도 있습니다. 이것은 정상입니다. Java를 처음 공부하기 시작했을 때 정적 변수가 무엇인지에 대해 머리를 감쌀 수 없었습니다. 하지만 별거 아니야. 나는 그것에 잠을 자고 몇 가지 출처를 더 읽은 다음 이해가 왔습니다. 면접 준비는 실제적인 것보다 학문적인 질문에 더 가깝습니다. 따라서 각 인터뷰 전에 자주 사용하지 않을 수 있는 내용을 검토하고 기억을 되살려야 합니다.

항상 그렇듯이 다음은 몇 가지 유용한 링크입니다.

읽어주셔서 감사합니다. 곧 만나요 :) 내 GitHub 프로필Java Core에 대한 상위 50개의 면접 질문 및 답변.  파트 2 - 5
코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다