멀티캠퍼스

[2026.05.06] - TIL 24일차 스레드, 네트워크

buckwheat 2026. 5. 7. 01:12

 

[1]스레드

1. 프로세스와 스레드

1) 프로세스

프로세스는 간단히 말해 실행 중인 프로그램이다. 프로그램을 실행하면 운영체제로부터 필요한 메모리와 자원을 할당받아 하나의 프로세스가 만들어진다. 하나의 프로세스는 프로그램을 실행하기 위한 자원과 함께, 실제 작업을 수행하는 하나 이상의 스레드로 구성된다.

 

2) 스레드

스레드는 프로세스 안에서 실제 작업을 수행하는 실행 단위이다. 하나의 프로세스 안에는 하나 이상의 스레드가 존재할 수 있으며, 각 스레드는 독립적인 작업 흐름을 가진다. 자바 프로그램도 결국 스레드를 통해 코드가 실행된다.

 

3) 메인 스레드

모든 자바 프로그램은 메인 스레드가 main() 메소드를 실행하면서 시작한다. 메인 스레드는 main() 메소드의 첫 줄부터 아래로 순서대로 코드를 실행하고, return을 만나거나 실행이 끝나면 종료된다.

필요한 경우에는 메인 스레드 외에 추가적인 작업 스레드를 만들어 여러 작업을 함께 실행할 수 있다. 이런 구조를 멀티 스레드라고 한다.

 

4) 프로세스 종료

싱글 스레드 프로그램에서는 메인 스레드가 종료되면 프로세스도 함께 종료된다. 하지만 멀티 스레드 프로그램에서는 실행 중인 스레드가 하나라도 남아 있다면 프로세스는 종료되지 않는다. 따라서 스레드가 언제 끝나는지도 중요하게 관리해야 한다.

 

 

2. 싱글 스레드와 멀티 스레드

 

1) 멀티 프로세스와 멀티 스레드

멀티 프로세스는 여러 개의 프로세스를 각각 독립적으로 실행하는 방식이다. 반면 멀티 스레드는 하나의 프로세스 안에서 여러 스레드가 동시에 작업을 수행하는 방식이다.

멀티 프로세스는 각각이 독립적이라는 장점이 있지만 자원 사용량이 더 크다. 멀티 스레드는 하나의 프로세스 안에서 자원을 공유하며 동작하기 때문에 자원을 더 효율적으로 사용할 수 있다.

 

2) 싱글 스레드와 멀티 스레드

싱글 스레드는 하나의 스레드만 이용해 작업을 처리한다. 그래서 한 작업이 끝나야 다음 작업을 실행할 수 있다. 작업 순서가 단순해서 이해하기는 쉽지만, 하나의 작업이 오래 걸리면 전체 프로그램도 함께 느려질 수 있다.

멀티 스레드는 여러 스레드가 나누어 작업을 수행한다. 한 스레드가 오래 걸리는 작업을 처리하는 동안 다른 스레드가 다른 일을 할 수 있기 때문에 응답성이 좋아질 수 있다. 예를 들어 사용자의 입력을 기다리는 동안 다른 작업을 동시에 처리할 수 있다.

 

3) 멀티 스레드의 장점

멀티 스레드는 자원을 보다 효율적으로 사용할 수 있고, 사용자에 대한 응답성을 높일 수 있다. 작업이 나뉘어 실행되기 때문에 프로그램이 더 부드럽게 동작하는 것처럼 보일 수 있고, CPU를 더 효율적으로 활용할 수도 있다. 또한 작업을 역할별로 분리할 수 있어 코드 구조를 나누는 데에도 도움이 된다.

 

4) 멀티 스레드의 단점

멀티 스레드는 장점이 많지만 그만큼 주의할 점도 많다. 여러 스레드가 같은 자원을 함께 사용할 경우 동기화 문제가 생길 수 있고, 서로 기다리기만 하다가 멈춰버리는 교착상태도 발생할 수 있다. 따라서 싱글 스레드보다 고려해야 할 요소가 많고 구현도 더 복잡해진다.

 

3. 스레드 생성과 실행

 

1) 스레드 생성 방법

자바에서 스레드를 만드는 방법은 크게 두 가지이다.

  • Thread 클래스를 상속받는 방법

이 경우 run() 메소드를 오버라이딩해서 스레드가 실행할 작업을 작성한 뒤, 객체를 생성하고 start()를 호출한다.

  • Runnable 인터페이스를 구현하는 방법

이 경우에도 run() 메소드를 구현하고, 그 객체를 Thread 객체에 전달한 뒤 start()를 호출한다.

보통은 상속보다 구현이 더 유연하므로 Runnable 방식을 많이 사용한다.

 

2) run()과 start()의 차이

스레드를 처음 배울 때 많이 헷갈리는 부분이 run()start()의 차이이다.

run()을 직접 호출하면 새로운 스레드가 만들어지는 것이 아니라, 그냥 일반 메소드를 호출하는 것처럼 현재 스레드에서 실행된다. 반면 start()를 호출하면 새로운 스레드가 생성되고, 그 안에서 run() 메소드가 실행된다.

그래서 멀티 스레드로 동작하게 하려면 run()이 아니라 반드시 start()를 호출해야 한다.

 

4. 스레드 스케줄링과 제어

1) 스레드 스케줄링

스레드 개수가 CPU 코어 수보다 많아지면, 어떤 스레드를 먼저 실행할지 순서를 정해야 한다. 이 과정을 스레드 스케줄링이라고 한다. 실제 실행 환경에서는 여러 스레드가 조금씩 번갈아가며 실행된다.

자바에서 스레드 스케줄링은 대표적으로 우선순위 방식과 순환 할당 방식으로 생각할 수 있다.

 

2) 우선순위 방식과 순환 할당 방식

우선순위 방식은 우선순위가 높은 스레드가 더 많은 실행 기회를 가지도록 하는 방식이다.

스레드마다 1부터 10까지 우선순위를 지정할 수 있고, 기본값은 5이다.

순환 할당 방식은 각 스레드에게 일정한 시간 조각을 나누어 주고 번갈아 실행시키는 방식이다. 이 시간 조각은 JVM이 정하며, 개발자가 직접 제어하기는 어렵다.

 

3) 스레드 제어

실행 중인 스레드는 여러 메소드를 통해 상태를 제어할 수 있다.

sleep()은 일정 시간 동안 스레드를 잠시 멈춘다.
join()은 다른 스레드의 작업이 끝날 때까지 기다린다.
yield()는 현재 실행 중인 스레드가 다른 스레드에게 실행을 양보하게 한다.
interrupt()sleep()이나 join() 등으로 대기 중인 스레드를 깨울 때 사용한다.
wait(), notify(), notifyAll()은 동기화된 상황에서 스레드 간 대기와 깨우기를 처리할 때 사용한다.

이 메소드들은 스레드의 실행 흐름을 조절하는 데 사용된다.

 

5. 동기화(Synchronized)

 

1) 동기화

멀티 스레드 환경에서는 여러 스레드가 하나의 객체나 데이터를 함께 사용하는 경우가 많다. 이때 동시에 접근하면 값이 꼬이거나 예상하지 못한 문제가 생길 수 있다. 이런 상황을 막기 위해 사용하는 것이 동기화이다.

동기화는 한 번에 하나의 스레드만 공유 자원에 접근할 수 있도록 잠금을 거는 방식이다. 다른 스레드는 잠금이 해제될 때까지 기다려야 한다.

 

2) 동기화 메소드와 동기화 블록

동기화는 두 가지 방식으로 자주 사용한다.

첫 번째는 동기화 메소드이다. 메소드 자체에 synchronized를 붙이면, 해당 메소드는 한 번에 하나의 스레드만 실행할 수 있다.

두 번째는 동기화 블록이다. 메소드 전체를 잠그지 않고, 정말 필요한 코드 부분만 synchronized(공유객체)로 감싸서 동기화할 수 있다. 이 방식은 필요한 부분만 잠글 수 있기 때문에 더 효율적으로 사용할 수 있다.

 


 

[2] 네트워크(Network)

 

1. 네트워크

 

1) 네트워크란

네트워크는 여러 대의 컴퓨터를 통신 회선으로 연결한 것을 말한다.
집에서 사용하는 홈 네트워크, 회사나 학교의 지역 네트워크, 그리고 인터넷도 모두 네트워크에 포함된다.

 

2) 서버와 클라이언트

네트워크로 연결된 컴퓨터들은 역할에 따라 서버와 클라이언트로 나눌 수 있다.

서버는 서비스를 제공하는 쪽이다. 클라이언트의 연결 요청을 받아들이고, 요청한 내용을 처리한 뒤 그 결과를 다시 돌려준다.

클라이언트는 서비스를 요청하는 쪽이다. 네트워크를 통해 필요한 데이터를 요청하고 응답을 받는 프로그램이라고 볼 수 있다.

 

3) IP주소와 포트

IP주소는 네트워크 상에서 컴퓨터를 식별하기 위한 번호이다.
쉽게 말하면 네트워크에 연결된 컴퓨터의 주소라고 생각하면 된다.

포트는 같은 컴퓨터 안에서 실행 중인 프로그램을 구분하기 위한 번호이다.
하나의 컴퓨터 안에서도 여러 프로그램이 동시에 네트워크를 사용할 수 있기 때문에, 어떤 프로그램과 통신할지 구분하기 위해 포트 번호가 필요하다.

클라이언트가 서버에 접속하려면 서버의 IP주소와 포트 번호를 알고 있어야 한다.

 

2. InetAddress 클래스

1) InetAddress란

InetAddress는 자바에서 IP주소를 다루기 위해 제공하는 클래스이다.
호스트 이름으로 IP주소를 찾거나, 내 컴퓨터의 IP주소를 확인할 때 사용할 수 있다.

 

2) 주요 메소드

  • getAddress() : IP주소를 byte 배열로 반환
  • getAllByName(String host) : 도메인에 연결된 모든 IP주소를 배열로 반환
  • getByAddress(byte[] addr) : byte 배열을 이용해 IP주소 객체 생성
  • getByName(String host) : 도메인 이름으로 IP주소 얻기
  • getCanonicalHostName() : 정규화된 호스트 이름 반환
  • getHostAddress() : 호스트의 IP주소 반환
  • getHostName() : 호스트 이름 반환
  • getLocalHost() : 현재 컴퓨터의 IP주소 반환
  • isMulticastAddress() : 멀티캐스트 주소인지 확인
  • isLoopbackAddress() : loopback 주소인지 확인

 

3. 소켓 프로그래밍

1) 소켓

소켓은 프로세스 간 통신에 사용되는 양쪽 끝 단을 말한다.
네트워크 통신에서는 데이터를 주고받기 위한 연결 창구 역할을 한다고 보면 된다.

 

2) 소켓 프로그래밍

소켓 프로그래밍은 소켓을 이용해 클라이언트와 서버가 데이터를 주고받는 프로그래밍 방식이다.
자바에서는 java.net 패키지의 여러 클래스를 사용해 소켓 통신을 구현할 수 있다.

 

4. TCP와 UDP

1) TCP

TCP는 연결 지향적 프로토콜이다.
속도는 상대적으로 느릴 수 있지만, 데이터가 정확하고 안정적으로 전달된다는 장점이 있다.

즉, 신뢰성이 중요한 통신에 적합하다.

 

2) UDP

UDP는 비연결 지향적 프로토콜이다.
속도는 빠르지만, 데이터가 반드시 도착한다는 보장이 없기 때문에 신뢰성은 TCP보다 낮다.

즉, 빠른 전송이 중요할 때 주로 사용한다.

 

5. TCP 소켓 프로그래밍

 

1 |  TCP

1) TCP 특징

TCP는 서버와 클라이언트가 1:1로 연결되어 통신하는 방식이다.
서버가 먼저 실행되어 있어야 하고, 클라이언트가 연결 요청을 보내면 서버가 이를 받아들인 뒤 통신이 시작된다.

자바에서는 TCP 소켓 프로그래밍을 위해 ServerSocketSocket 클래스를 사용한다.

 

2) 서버용 TCP 소켓 프로그래밍 순서

서버 프로그램은 보통 다음 순서로 동작한다.

  1. 서버의 포트 번호를 정한다.
  2. 서버용 소켓 객체를 생성한다.
  3. 클라이언트의 접속 요청을 기다린다.
  4. 요청이 오면 accept()로 수락하고, 해당 클라이언트와 연결된 소켓 객체를 생성한다.
  5. 연결된 클라이언트와 입출력 스트림을 만든다.
  6. 필요하면 보조 스트림을 연결해 성능을 높인다.
  7. 스트림을 통해 데이터를 읽고 쓴다.
  8. 통신을 종료한다.

3) 클라이언트용 TCP 소켓 프로그래밍 순서

클라이언트 프로그램은 보통 다음 순서로 동작한다.

  1. 서버의 IP주소와 포트 번호를 이용해 클라이언트용 소켓 객체를 생성한다.
  2. 서버와의 입출력 스트림을 연다.
  3. 필요하면 보조 스트림을 연결한다.
  4. 스트림을 통해 데이터를 읽고 쓴다.
  5. 통신을 종료한다.
  6. UDP 소켓 프로그래밍

2 | UDP

1) UDP 특징

UDP는 연결 지향적이지 않기 때문에, TCP처럼 연결 요청을 받아줄 서버 소켓 개념이 따로 필요하지 않다.
자바에서는 DatagramSocketDatagramPacket을 이용해 데이터를 주고받는다.

 

2) 서버용 UDP 소켓 프로그래밍 순서

  1. 서버의 포트 번호를 정한다.
  2. DatagramSocket 객체를 생성한다.
  3. 클라이언트의 IP주소를 담을 InetAddress 객체를 만든다.
  4. 전송할 메시지를 byte 배열로 바꾼다.
  5. 메시지를 DatagramPacket 객체에 담는다.
  6. 소켓을 이용해 메시지를 전송한다.
  7. 소켓을 닫는다.

3) 클라이언트용 UDP 소켓 프로그래밍 순서

  1. 서버가 보낸 메시지를 받을 byte 배열을 준비한다.
  2. DatagramSocket 객체를 생성한다.
  3. 메시지를 받을 DatagramPacket 객체를 준비한다.
  4. byte 배열로 받은 메시지를 문자열로 바꾸어 출력한다.
  5. 소켓을 닫는다.

네트워크는 여러 컴퓨터를 연결해 데이터를 주고받는 구조이고, 서버와 클라이언트는 그 안에서 역할을 나눈 개념이다.
통신을 하려면 IP주소와 포트 번호가 필요하고, 자바에서는 InetAddress 클래스를 이용해 IP주소를 다룰 수 있다.

소켓 프로그래밍은 소켓을 이용해 데이터를 주고받는 방식이며, TCP와 UDP 두 가지 방식으로 나뉜다.

  • TCP : 연결 지향, 느리지만 안정적
  • UDP : 비연결 지향, 빠르지만 신뢰성 낮음