[Java] 자바 스레드 (Thread) 처리 방법

반응형

컴퓨터 프로그래밍에는 프로세스라는 개념이 있습니다. 프로세스란 실행환경이라고 생각하면 됩니다. 컴퓨터에는 메모리와 CPU가 있고 특정 프로그램이 할당한 메모리 공간과 그 외 자원들을 포함한 실행 환경을 프로세스라고 합니다. 이는 분명히 프로그램이나 애플리케이션과는 조금 다른 개념입니다. 한 개의 프로그램 또는 애플리케이션에 여러 개의 프로세스가 포함될 수 있기 때문입니다.

 

위에서 설명한 프로세스와 비슷한 하위 개념인 스레드가 있습니다. 스레드는 다른말로 lightweight process (경량 프로세스)라고도 합니다. 이유는 프로세스를 만드는 비용에 비해 스레드를 만드는 비용이 적게 들어가기 때문입니다. 스레드들은 어떠한 프로세스에 종속되며 프로세스에 할당된 메모리 또는 파일과 같은 자원을 스레드들끼리 공유가 가능합니다.

 

멀티 스레드 (Multi thread)

자바의 JVM은 기본적으로 싱글 프로세스로 동작하지만 멀티 스레드를 가질 수 있습니다. 멀티 프로세스의 경우 여러 개의 CPU를 사용하여 여러 프로세스를 동시에 수행합니다. 이것을 멀티 프로세싱이라고 합니다. 이와 비슷한 하위 개념으로  멀티 스레드 (multi thread)라는것이 있습니다. 스레드가 여러 개 일 때 동시에 실행하는 것이죠. 멀티 스레드는 자원을 공유하기 때문에 시스템 자원의 낭비가 적지만 반대로 공유하는 자원의 간섭이 생겨서 시스템이 불 안정해질 수 있습니다. 하지만 동기화 같은 기법을 잘 사용해서 프로그래밍하면 사용자의 응답성을 높일 수 있습니다.

 

기본적인 Java의 Thread 구현 방법

 방법 1 - Thread를 상속받아 run() 메서드를 Override 합니다. 그리고 객체를 생성한 뒤 start() 메서드로 실행이 가능합니다.

 

 

 방법 2 - Runnable 인터페이스를 구현하고 run() 메서드를 Override 합니다. 그리고 새로운 Thread 객체의 인자로 포함한뒤 start 메서드로 실행이 가능합니다.

위의 두 방법 중 Runnable 인터페이스를 구현했을 때에 작업과 스레드 객체를 분리할 수 있는 이점이 있습니다. 또한 자바는 다중상속이 되지 않기 때문에 Runnable로 구현했을 경우 다른 클래스 상속이 가능하지만 Thread를 상속받아 구현한 경우 다른 클래스의 상속이 불가능합니다.

 

 

 

람다 표현식

 Runnable 인터페이스의 run() 함수의 경우 @FuntionalInterface이기 때문에 다음과 같이 람다 표현법 적용이 가능합니다.

@FuntionalInterface

 

 

 

메서드 레퍼런스

 다음과 같이 인스턴스 또는 스테틱 형태의 메서드 레퍼런스를 사용할 수 있습니다.

 

 

ExecutorService

 ExecutorService 서비스 객체를 만들어서 Worker를 만들어 Thread Pool에서 작업을 처리할 수 있습니다. ExecutorService는 Thread Pool을 만들어서 보장된 동작이 가능합니다. 만약 사용이 종료되었다면 shutdown(); 메서드를 사용해 종료해주어야 합니다.

  • CachedThreadPool - 스레드 처리 자체를 캐싱합니다. (60초 동안 작업이 없다면 제거)
  • FixedThreadPool - n개의 갯수를 가지는 스레드 풀로 사용자가 직접 지정합니다.
  • SingleThreadExecute - 싱글 스레드로 처리합니다.

 

싱글, 멀티 스레드와 문맥 교환

스레드 처리를 통해 사용자의 응답성을 높일 수 있는 장점이 있지만 컴퓨터에서 동시에 처리 가능한 최대 작업 수는 CPU의 개수와 비례하며 병렬적으로 처리할 수 있는 성능에 따라서 처리할 수 있는 스레드의 수가 늘어납니다. 하지만 CPU의 성능에 제약이 있고 스레드의 개수가 많이 늘어나게 되면 병렬적으로 처리는 하지만 한 번에 처리할 수 있는 스레드는 특정 Core당 하나씩 처리되기 때문에 작업이 교체될 때마다 스레드 간의 문맥 교환(Context Switching)이 일어납니다. 싱글 스레드일 경우 이러한 문맥 교환이 일어나지 않게 되므로 오히려 시스템의 성능이 좋지 않다면 여러 스레드를 만들어서 동작하는 것보다 더 효율적으로 동작할 수 있습니다. 이 처럼 스레드를 적절히 사용하면 좋은 성능을 발휘할 수 있지만 시스템을 고려하지 않고 너무 많이 사용하더라도 문맥 교환에 의해서 시스템 성능이 떨어질 수 있습니다.

 

동기화 블록과 동기화 메서드

 다음과 같은 블록안에서 동작을 하게 되면 스레드 간섭(thread interference)을 막을 수 있습니다.

 

 

 스레드 간섭과, 메모리 일관성오류를 제거하기 위해 동기화를 사용합니다. 다음 처럼 블록 형태로도 사용이 하고 메서드 자체를 동기화 메서드로 만들 수도 있습니다.

 

 

 다음은 동기화 메서드 처리 구문입니다. 메서드에에 synchroized라고 추가해주면 됩니다.

반응형

댓글

Designed by JB FACTORY