[Java] 45. 스레드 풀과 Executor 프레임워크(2)
·
Java/멀티스레드&동시성
[Java] 44. 스레드 풀과 Executor 프레임워크(1)
·
Java/멀티스레드&동시성
스레드 풀과 Executor 프레임워크(1)#Java/멀티스레드(복습할 때 왠만하면 강의 자료 전체를 보는게 좋긴 할듯)이전 챕터까지 우리는 Runnable 을 만들고 Thread 를 직접 생성해서 사용했다. 하지만 실무에서 직접 스레드를 생성해서 사용하면 다음과 같은 문제가 있다.스레드 생성 시간으로 인한 성능 문제스레드 관리 문제Runnable 인터페이스의 불편함1. 스레드 생성 비용으로 인한 성능 문제스레드를 사용하려면 먼저 스레드를 생성해야 한다. 그런데 스레드는 다음과 같은 이유로 매우 무겁다.메모리 할당: 각 스레드는 자신만의 호출 스택(call stack)을 가지고 있어야 한다. 이 호출 스택은 스레드가 실행되는 동안 사용하는 메모리 공간이다. 따라서 스레드를 생성할 때는 이 호출 스택을 위..
[Java] 43. 동시성 컬렉션
·
Java/멀티스레드&동시성
동시성 컬렉션#Java/멀티스레드정리이전 챕터에서 원자적 연산에 대해 배웠고, 원자적 연산이 아닌 경우에 멀티스레드 상황에서 문제가 발생할 수 있음을 확인했다.여러 스레드가 동시에 접근해도 괜찮은 경우를 스레드 세이프(Thread Safe) 하다고 한다.java.util 패키지에 소속되어 있는 컬렉션 프레임워크는 원자적인 연산을 제공할까?예를 들어서 하나의 ArrayList 인스턴스에 여러 스레드가 동시에 접근해도 괜찮을까? (= 스레드 세이프할까?)컬렉션에 데이터를 추가하는 add() 메서드를 생각해보자. 단순히 컬렉션에 데이터를 하나 추가하는 것뿐이다. 따라서 이것은 마치 연산이 하나만 있는 원자적인 연산처럼 느껴진다. 원자적인 연산은 쪼갤 수 없기 때문에 멀티스레드 상황에 문제가 되지 않는다.하..
[Java] 42. CAS - 동기화와 원자적 연산
·
Java/멀티스레드&동시성
CAS - 동기화와 원자적 연산#Java/멀티스레드정리원자적 연산이란?컴퓨터 과학에서 사용하는 원자적 연산(atomic operation)의 의미는 해당 연산이 더 이상 나눌 수 없는 단위로 수행된다는 것을 의미한다. 즉, 원자적 연산은 중단되지 않고, 다른 연산과 간섭 없이 완전히 실행되거나 전혀 실행되지 않는 성질을 가지고 있다. 따라서 멀티스레드 상황에서 다른 스레드의 간섭 없이 안전하게 처리된다.예를 들어서 다음과 같은 필드가 있을 때volatile int i = 1;다음 연산은 둘로 쪼갤 수 없는 원자적 연산이다.i = 1;왜냐하면 이 연산은 다음 단 하나의 순서로 실행되기 때문이다.오른쪽에 있는 1 의 값은 왼쪽의 i 변수에 대입한다.하지만 다음 연산은 원자적 연산이 아니다.i = i + 1;..
[Java] 41. 생산자 소비자 문제(2)
·
Java/멀티스레드&동시성
생산자 소비자 문제(2)#Java/멀티스레드정리이전 챕터에서 발견했던 생산자가 생산자를 깨우고, 소비자가 소비자를 깨우는 비효율 문제를 어떻게 해결해보자.해결 방안핵심은 생산자 스레드는 데이터를 생성하고, 대기중인 소비자 스레드에게 알려주어야 한다. 반대로 소비자 스레드는 데이터를 소비하고, 대기중인 생산자 스레드에게 알려주면 된다. 결국 생산자 스레드가 대기하는 대기 집합과, 소비자 스레드가 대기하는 대기 집합을 둘로 나누면 된다.대기 집합을 어떻게 분리할 수 있을까? 바로 앞서 학습한 Lock , ReentrantLock 을 사용하면 된다.먼저, synchronized , Object.wait() , Object.notify() 를 통해 작성한 코드를 Lock 인터페이스와 ReentrantLock 구..
[Java] 40. 생산자 소비자 문제(1)
·
Java/멀티스레드&동시성
생산자 소비자 문제(1)#Java/멀티스레드생산자 소비자 문제란?생산자 소비자 문제는 멀티스레드 프로그래밍에서 자주 등장하는 동시성 문제 중 하나로, 여러 스레드가 동시에 데이터를 생산하고 소비하는 상황을 다룬다. 아주 중요한 내용임!프린터 예제 - 그림기본 개념생산자(Producer): 데이터를 생성하는 역할을 한다. 예를 들어, 파일에서 데이터를 읽어오거나 네트워크에서 데이터를 받아오는 스레드가 생산자 역할을 할 수 있다.앞서 프린터 예제에서 사용자의 입력을 프린터 큐에 전달하는 스레드가 생산자의 역할이다.소비자(Consumer): 생성된 데이터를 사용하는 역할을 한다. 예를 들어, 데이터를 처리하거나 저장하는 스레드가 소비자 역할을 할 수 있다.앞서 프린터 예제에서 프린터 큐에 전달된 데이터를 받아..
[Java] 39. 고급 동기화 - concurrent.Lock
·
Java/멀티스레드&동시성
고급 동기화 - concurrent.Lock#Java/멀티스레드정리Synchronized의 단점synchronized 단점무한 대기: BLOCKED 상태의 스레드는 락이 풀릴 때 까지 무한 대기한다.특정 시간까지만 대기하는 타임아웃X중간에 인터럽트X공정성: 락이 돌아왔을 때 BLOCKED 상태의 여러 스레드 중에 어떤 스레드가 락을 획득할 지 알 수 없다. 최악의 경우 특정 스레드가 너무 오랜기간 락을 획득하지 못할 수 있다.결국 더 유연하고, 더 세밀한 제어가 가능한 방법들이 필요하게 되었다.이런 문제를 해결하기 위해 자바 1.5부터 java.util.concurrent 라는 동시성 문제 해결을 위한 라이브러리 패키지가 추가된다.LockSupportjava.util.concurrent 라이브러리에는 수..
[Java] 38. 동기화 - synchronized
·
Java/멀티스레드&동시성
동기화 - synchronized#Java/멀티스레드정리멀티스레드를 사용할 때 가장 주의해야 할 점은, 같은 자원(리소스. ex) 인스턴스의 필드)에 여러 스레드가 동시에 접근할 때 발생하는 동시성 문제이다. (참고로 여러 스레드가 접근하는 자원을 공유 자원이라 한다. 대표적인 공유 자원은 인스턴스의 필드(멤버 변수)이다. )동시성 문제가 어떤 문제인지 이해하기 위해 간단한 은행 출금 예제를 하나 만들어보자.은행 출금 예제 - volatile 미적용package thread.sync;import static util.MyLogger.log;import static util.ThreadUtils.sleep;public class BankAccountV1 implements BankAccount { p..
[Java] 37. 메모리 가시성
·
Java/멀티스레드&동시성
메모리 가시성#Java/멀티스레드정리volatile과 메모리 가시성volatile 은 자바에서 예약된 키워드이다. (패키지 이름으로 사용할 수 없다). volatile 이 하는 역할은 무엇일까?이전 챕터에서 runFlag에 volatile 키워드를 사용했던 것을 기억할 것이다. 만약 여기서 volatile 키워드를 제거하면 어떻게 될까?public static void main(String[] args) { MyTask task = new MyTask(); Thread t = new Thread(task, "work"); // ...}static class MyTask implements Runnable { boolean runFlag = true; /..
[Java] 36. 스레드 제어와 생명 주기(2)
·
Java/멀티스레드&동시성
스레드 제어와 생명 주기(2)#Java/멀티스레드정리작업 중단 - 1. 변수특정 스레드의 작업을 중간에 중단하려면 어떻게 해야할까?public class ThreadStopMainV1 { public static void main(String[] args) { MyTask task = new MyTask(); Thread thread = new Thread(task, "work"); thread.start(); sleep(4000); log("작업 중단 지시 runFlag=false"); task.runFlag = false; } static class MyTask implements Runnable { ..