Java - Multithread Synchronization Issues Basic


  • 우리가 멀티스레드의 동기화 문제를 알기 전에, 먼저 멀티 스레드가 뭔지를 알아야한다.

  • 자세하고 깊은 내용은 추후 멀티스레드에 공부할 때 깊이 공부할 예정이며, 우선 오늘은 기초적인 개념만 이해하고 공부하였다.

  • 정말 쉬운 웹 프로그래밍을 예시로 들면, 한 사용자만의 동작을 허용하는걸 단일 스레드라고 하며, 여러 사용자가 동시에 해당 프로그램을 사용할 수 있다면 그게 멀티 스레드이다.

  • 스프링을 활용해서 웹 프로그래밍을 하면, 아파치를 많이 사용할텐데 아파치는 기본적으로 멀티 프로세스로 구현되어있고, 설정에 따라 멀티 스레드를 같이 운용할 수 있다. 그래서 위와 같은 병행 실행이 가능한데, 여러 사용자가 하나의 static에 접근한다거나, 같은 객체에 접근하게 될 경우 발생할 수 있는 문제가 바로 [동기화 문제]이다

  • 기본적인 예시코드이다
      public class SynchronizationExample {
          public static void main(String[] args) {
              SharedResource sharedResource = new SharedResource();
    
              Thread thread1 = new Thread(() -> {
                  for (int i = 0; i < 1000; i++) {
                      sharedResource.increment();
                  }
              });
    
              Thread thread2 = new Thread(() -> {
                  for (int i = 0; i < 1000; i++) {
                      sharedResource.increment();
                  }
              });
    
              thread1.start();
              thread2.start();
    
              try {
                  thread1.join();
                  thread2.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
    
              System.out.println("Final Count: " + sharedResource.getCount());
          }
          }
    
          class SharedResource {
          private int count = 0;
    
          public void increment() {
              count++;
          }
    
          public int getCount() {
              return count;
          }
      }
    
  • 이렇게 될 경우, 스레드 1과 2에서 동시에 해당 객체에 접근을 하게 되고, 각자 1000번씩 숫자를 증가시킨다.

  • 저렇게 동시에 한 객체에 접근하게 될 때 문제가 발생하게 된다.( 물론 스레드별로 각자 인스턴스를 만든다면 문제는 없다. )

  • 이런 경우는 저렇게 객체 뿐아니라, 싱글턴 패턴에서도 발생할 수 있다.

  • 해당 문제를 해결하기 위해서는 동시에 접근할 수 있는 메서드에 synchronized 를 붙여서 동기화 작업을 해줘야 한다.
      public class SynchronizationExample {
          public static void main(String[] args) {
              SharedResource sharedResource = new SharedResource();
    
              Thread thread1 = new Thread(() -> {
                  for (int i = 0; i < 1000; i++) {
                      sharedResource.increment();
                  }
              });
    
              Thread thread2 = new Thread(() -> {
                  for (int i = 0; i < 1000; i++) {
                      sharedResource.increment();
                  }
              });
    
              thread1.start();
              thread2.start();
    
              try {
                  thread1.join();
                  thread2.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
    
              System.out.println("Final Count: " + sharedResource.getCount());
          }
      }
    
      class SharedResource {
          private int count = 0;
    
          public void synchronized increment() {
              count++;
          }
    
          public int getCount() {
              return count;
          }
      }
    
  • 이렇게 increment 라는 메서드에 synchronized를 붙여줌으로써, 동시에 접근할 경우 하나의 스레드가 작업을 마치는 동안 다른 스레드들은 순차적으로 기다려야 한다.

  • 다만 synchronized를 너무 많이 사용하게 되면 그만큼 많은 사용자들이 오래 기다려야 할 수 있으므로, 너무 남발하는 것은 좋은 방법이 아니다. 자세한 건 추후 멀티 스레드를 공부하며 더 작성하겠지만 java.util.concurrent 를 사용하는 것도 좋은 방법이다. ( HashMap 대신 ConcurrentHashMap을 사용하는 것과 같은 맥락 )



결론

  • 결론은 우리가 자바를 통해 프로그래밍을 할 때, 클래스를 만들고 static을 만들고 할 것이다.
  • 이 때 멀티 스레드, 병렬 프로그래밍을 염두하고 코드를 작성해야한다.
  • 동기화 문제 라는 것이 무엇인지를 정확히 알고 있어야 한다.






results matching ""

    No results matching ""