26. 스레드

Jan 03, 2024
26. 스레드
스레드 그림

프로세스

💡
프로세스는 코드, 코드 실행, 데이터 처리등 프로그램의 기능을 전체적으로 묶은 동작을 실행하는 단위를 의미한다.
 

멀티 태스킹

💡
여러 개의 태스크(작업)를 동시에 실행하는 기법으로 다수의 작업을 동시에 실행하면 컴퓨터의 효율을 높일 수 있다 운영체제가 CPU의 시간을 쪼개어서 작업들에 시간을 할당하기 때문에 작업들이 동시에 수행 되는 것처럼 보인다. 그러나 예외로 멀티 코어를 가지고있는 CPU라면 실제로도 동시에 실행 될 것이다.
 

멀티 스레딩

💡
하나의 애플리케이션 안에서도 여러가지 작업을 동시에 하는 것을 의미하며, 예시로 동영상을 재생하는 어플은 인터넷을 통하여 mp4파일을 내려 받으면서, 동시에 압축을 풀어서 동영상을 재생한다. 이들 각각의 작업은 스레드라고한다. 스레드는 실이라는 의미로 하나의 실행 흐름을 의미한다.
 

프로세스와 스레드

💡
컴퓨터에는 프로세스와 스레드라는 2가지의 실행 단위가 있다. 가장 근본적인 프로세스는 자신만의 데이터를 가지는 데 반하여
스레드들은 모두 동일한데이터를 공유한다. (각 스레드는 자신만의 스택을 가지고 있지만, 코드, 데이터, 힙 영역은 모든 스레드가 공유합니다. 따라서, 한 스레드가 변수의 값을 변경하면, 다른 스레드에서도 변경된 값을 볼 수 있습니다. 이러한 공유 메모리를 통해 스레드 간에 데이터를 주고받을 수 있다)
스레드는 또한 일꾼이라는 뜻으로도 불리며 여러개의 스레드가 코드에서 있더라도 여러개의 존재가 존재하는것이 아닌 서로 교차하면서 사람이 인식하지 못할 빠른 속도로 일한다.
 

멀티 스레딩을 하는 이유

💡
응용 프로그램을 보다 빠르게 실행하기 위하여 사용한다. 최근의 CPU는 속도가 매우 빠르며 여러개의 코어가 포함 돼있어 하나의 스레드는 모든 코어를 이용할 수 없다. 그러므로 멀티 스레딩을 사용하면 여러 코어를 최대한 활용 할 수 있다. 예시로 게임에서 사용자가 키보드나 마우로 입력을 하면 네트워크에 무언가를 업로드 하는 동시에 화면도 그려야한다. 이것을 하나의 스레드가 동시에 일을 하지 못하기 때문에 여러개의 스레드가 필요하다.
 

멀티 스레딩의 문제점

💡
여러 스레드들이 같은 데이터를 공유하게되면 동기화가 안된 까다로운 문제가 발생한다 예시로 버스에 좌석이 3개뿐인데 두 사람이 서버에 동시에 접근하여서 좌석을 2개씩 예약한다면 문제가 될것이다. 자바에는 이문제를 해결 할 수 있는 도구들 포함되어있다

스레드(Thred)클래스

스레드 클레스
 

동기화

💡
스레드들은 동일한 데이터를 공유하기 때문에 효율적으로 작업 할 수 있지만, 동일한 메모리를 사용하기 때문에 2가지의 문제가 발생 할 수 있다. 하나는 스레드 간섭이고 또 하나는 메모리 불일치 오류이다. 스레드 간섭은 여러개의 스레드가 공유된 데이터에 동시에 접근 할때 발생하는 것으로 예시로 공유 프린터를 한사람이 사용하고 있는데, 다른 사람이 공유 프린터 사용을 시도하면 두사람의 출력이 섞이게 될 것이다.(프린팅 큐가 없는 경우에) 메모리 불일치 오류는 스레드에 따라서 공유된 메모리의 값이 일치하지 않는 현상으로 이러한 오류를 막는 도구를 동기화 라고 한다.
예제
package ex13; class Printer { void print(int[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class MyThread1 extends Thread { Printer prn; int[] myarr = {10, 20, 30, 40, 50}; MyThread1(Printer prn) { this.prn = prn; } public void run() { prn.print(myarr); } } class MyThread2 extends Thread { Printer prn; int[] myarr = {1, 2, 3, 4, 5}; MyThread2(Printer prn) { this.prn = prn; } public void run() { prn.print(myarr); } } public class TestSynchro { public static void main(String[] args) { Printer printer = new Printer(); MyThread1 t1 = new MyThread1(printer); MyThread2 t2 = new MyThread2(printer); t1.start(); t2.start(); } }
스레드 간섭으로 이렇게 엉키게 된다.
스레드 간섭으로 이렇게 엉키게 된다.
 

스레드 동기화 방법

💡
공중 화장실을 예시로 들면 한명의 사용자가 사용하고 있으면 다른 사용자는 사용이 끝날 때 까지 기다려야한다. 이러한 부분을 (공중 화장실)임계 영역이라고한다.
💡
위 문제를 막기 위해 자바에서 다음과 같은 3가지 방법을 제공하고 있다.
동기화 3가지
  • 동기화 메소드
  • 동기화 블록
  • 정적 동기화
Print 객체는 임계영역으로 생각 할 수있고 synchronized 키워드를 사용하여서 메소드나
코드에 락을 걸어야한다. 즉 하나의 스레드가 임계 영역에 진입하면 다른 스레드들을 락이 풀릴때 까지 기다리게 해야한다.
 
동기화 메소드 사용
💡
synchronized 키워드를 붙여 하나의 스레드가 동괴화 된 메소드를 실행하고있으면 메소드를 실행하고있으면 그 스레드가 종료할 때까지 다른 모든 스레드는 중지된다. 이것은 스레드 간섭문제를 해결 할 수 있으며 동기화된 메소드가 종료되면 자동적으로 이후의 메소드 호출은 변경된 상태만을 볼 수 있다. 이것은 메모리 불일치 오류 문제를 해결한다
package ex13; import ex16.SYNCHRONIZED; class Printer { synchronized void print(int[] arr) { for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class MyThread1 extends Thread { Printer prn; int[] myarr = {10, 20, 30, 40, 50}; MyThread1(Printer prn) { this.prn = prn; } public void run() { prn.print(myarr); } } class MyThread2 extends Thread { Printer prn; int[] myarr = {1, 2, 3, 4, 5}; MyThread2(Printer prn) { this.prn = prn; } public void run() { prn.print(myarr); } } public class TestSynchro { public static void main(String[] args) { Printer printer = new Printer(); MyThread1 t1 = new MyThread1(printer); MyThread2 t2 = new MyThread2(printer); t1.start(); t2.start(); } }
notion image
동기화 블록 사용
💡
동기화된 블록은 블록 지정한 내부만 동기화 되서 메서드 전에 하기보단 내부에서 몇 줄만 동기화 하려 할때 사용
교착(데드락)
💡
동기화가 임계영역 문제는 해결하지만 동일한 자원을 접근하려고, 동기화를 기리면서 대기하는 스레드들이 많아지면 자바 가상 머신이 느려지거나 일시 중단되기도 한다.| 이것을 교착 상태라고한다.
Thread t1 = new Thread(() -> { synchronized (res1){ System.out.println("Thread 1: 자원 1 획득"); try { Thread.sleep(100); } catch (Exception e) { } synchronized (res2){ System.out.println("Thread1: 자원2 획득"); } } });
notion image

해결

💡
T2도 T1이랑 똑같이 잠금 순서를 바꿔주면 올바르게 순차적 진행으로 상태 해결
package ex13; public class DeadLockTest { public static void main(String[] args) { final String res1 = "Gold"; final String res2 = "Silver"; Thread t1 = new Thread(() -> { synchronized (res1){ System.out.println("Thread 1: 자원 1 획득"); try { Thread.sleep(100); } catch (Exception e) { } synchronized (res2){ System.out.println("Thread1: 자원 2 획득"); } } }); Thread t2 = new Thread(() -> { synchronized (res1){ System.out.println("Thread 2: 자원 1 획득"); try { Thread.sleep(100); } catch (Exception e) { } synchronized (res2){ System.out.println("Thread2: 자원 2 획득"); } } }); t1.start(); t2.start(); } }
notion image
 
 
 
 
Share article
RSSPowered by inblog