스레드를 알기 전에 알아가는 컴퓨터 상식
스레드와 프로세스
- 프로세스 → 하드 드라이브에서 메모리로 로드 된 프로그램을 프로세스라고 합니다. 프로세스를 관리하는 역할은 프로세서(CPU)가 맡습니다.
- 스레드 → 모든 프로세스는 최소 하나의 스레드를 가지고 있습니다. 스레드는 프로세스 내에서 실행되는 작업의 단위로, CPU가 이를 논리적으로 처리합니다. 이때 스레드는 자기 자신을 스레드로 처리 할 수 있다.
- 멀티스레딩 → CPU가 여러 스레드를 동시에 관리하면서, 여러 작업을 동시에 처리하는 것처럼 보이게 하는 기법입니다. 멀티스레딩은 프로그램의 속도를 빠르게 하는 것이 아니라, 여러 작업을 동시에 수행할 수 있게 해서 사용자 경험(UX)를 향상시킵니다.
메모리 관리
- 랜덤 액세스 메모리 (RAM) → 데이터를 임시로 저장하는 공간으로, CPU가 빠르게 데이터를 읽고 쓸 수 있습니다. 다이렉트로 이동한다.
- 스왑 → 메모리가 부족할 때, 현재 사용하지 않는 데이터를 하드 드라이브로 옮기고 (스왑 아웃), 필요한 데이터를 하드 드라이브에서 메모리로 불러오는 (스왑 인) 과정입니다.
- 가상 메모리 → 메모리가 부족할 때, 하드 드라이브의 일부 공간을 마치 추가적인 메모리인 것처럼 사용하는 기법입니다.
하드 드라이브
- 하드 드라이브에 저장하는 과정 → 메모리에서 하드 드라이브로 데이터를 이동시키는 과정을 커밋, 라이트, 또는 인풋이라고 합니다.
- 하드 드라이브에서 불러오는 과정 → 하드 드라이브에서 메모리로 데이터를 이동시키는 과정을 로드, 아웃풋, 또는 알로케이트라고 합니다.
- 시크 → 하드 드라이브의 읽기/쓰기 헤드가 데이터를 찾아가는 과정을 말합니다.
I/O와 웨이트 시간
- I/O(Input/Output) → 메모리와 하드 드라이브 사이에서 데이터가 오고 가는 모든 과정을 I/O라고 합니다. I/O는 CPU 처리 시간에 비해 상대적으로 많은 시간이 소요됩니다.
- 웨이트 시간 → CPU가 I/O 또는 다른 프로세스의 종료 등을 기다리는 시간을 말합니다.
추가적으로 알면 좋을 내용
- 컨텍스트 스위칭 → CPU가 여러 프로세스 또는 스레드를 돌아가면서 처리하기 위해, 현재 상태를 저장하고 다음 작업의 상태를 불러오는 과정을 말합니다.
- 라운드 로빈 스케줄링 → CPU의 시간을 각 프로세스에게 동일하게 할당하여, 모든 프로세스가 공평하게 CPU 시간을 사용하도록 하는 스케줄링 알고리즘입니다.
- 스레드의 생명 주기 → 스레드는 '생성', '실행 가능', '실행 중', '대기', '종료' 등의 상태를 가지며, 이러한 상태들은 스케줄러에 의해 관리됩니다. 스레드가 가지는 독립적인 스택에는 스레드가 수행하는 함수의 호출 정보와 지역 변수 등이 저장됩니다.
- 콜백 → 이벤트가 발생했을 때 시스템이 자동으로 호출하는 함수나 메소드를 말한다.
스레드(Thread)
- 작업을 진행하는 것을 “스레드”라 한다.
- 스레드는 실이라는 의미로, “하나의 실행 흐름(thread of execution)”을 의미한다.
- 스레드가 모여 있는 것을 “멀티 스레딩(multi-threading)”이라 한다.
- 자바는 스레드가 하나라도 살아있으면 종료되지 않는다.
- 메인 스레드는 가장 먼저 종료가 되는데, 종료되고 남아있는 서브 스레드들이 동시 실행되는데 이를 “컨텍스트 스위칭”이라 한다.
CPU가 풀파워로 돌면 다른 곳에서 이벤트가 발생 할 수 없다.
→ 이때 풀파워의 틈을 만드는게 “sleep”이다.
→ 이 틈에 움직이는 것을 “컨텍스트 스위칭”이라 한다.
- 동기식 실행과 비동기식 실행 → 스레드는 동기식과 비동기식 둘 다 처리가 가능하다.
- 작업을 순차적으로 진행하는 실행이다.
- 여러 작업을 동시에 진행하는 실행이다.
동기식 실행
비동기식 실행
동기적의 뜻!
데이터의 관점에서는 “데이터의 일관성(동일성)”을 뜻하고,
프로그래밍 관점에서는 ”일의 순서가 있다”를 뜻한다.
- 자바에서 스레드를 생성하여 작업하는 방법은 총 2가지가 있다. → Thread 클래스를 상속하는 방법 / Runnable 인터페이스를 구현하는 방법
- 스레드는 람다식을 이용하여 작성도 가능하다.
스레드 코드 설명
- 스레드 기본 코드와 sleep을 사용한 코드 → 비동기식의 형태로 출력이 된다.
package ex16.example1; public class ThreadEx01 { public static void sub1() { for (int i = 1; i <= 5; i++) { try { System.out.println("start1 thread : " + i); Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public static void sub2() { for (int i = 1; i <= 5; i++) { try { System.out.println("start2 thread : " + i); Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } // main thread public static void main(String[] args) { Thread t1 = new Thread(() -> { sub1(); }); t1.start(); // 실을 만드는 것 Thread t2 = new Thread(() -> { sub2(); }); t2.start(); // 실을 시작하는것 } // main 스레드 종료 }
출력 결과
- Runnable을 사용한 코드 → 2개의 스레드가 실행되면서 스레드의 출력이 서로 섞여서 나온다.
package ex16; class MyRunnable implements Runnable { String myName; public MyRunnable(String name) { this.myName = name; } public void run() { for (int i = 0; i <= 10; i++) { System.out.println(myName + i + " "); } } } public class TestThread { public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable("A")); Thread t2 = new Thread(new MyRunnable("B")); t1.start(); t2.start(); } }
출력 결과
- 람다식을 활용한 코드
package ex16; public class LambdaTest { public static void main(String[] args) { Runnable task = () -> { for (int i = 0; i <= 10; i++) { System.out.println(i + " "); } }; new Thread(task).start(); } }
출력 결과
- 스레드를 상속받아 JFrame과 같이 사용한 코드 → 직접 코드를 출력해보면 더욱 쉽게 이해가 되는 코드이다.
package ex16; import javax.swing.*; import java.awt.*; public class CountDownTest extends JFrame { private JLabel label; class MyThread extends Thread { public void run() { for (int i = 0; i <= 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } label.setText(i + ""); } } } public CountDownTest() { setTitle("카운트다운"); setSize(400, 150); label = new JLabel("Start"); label.setFont(new Font("Serif", Font.BOLD, 100)); add(label); setVisible(true); new MyThread().start(); } public static void main(String[] args) { CountDownTest t = new CountDownTest(); } }
Share article