자바의 멀티스레딩
JVM(Java Virtual Machine)은 병렬 컴퓨팅을 지원합니다 . 모든 계산은 하나 이상의 스레드 컨텍스트에서 수행할 수 있습니다. 여러 스레드에 대해 동일한 리소스 또는 개체에 대한 액세스를 쉽게 설정할 수 있을 뿐만 아니라 단일 코드 블록을 실행하도록 스레드를 설정할 수 있습니다.
모든 개발자는 여러 스레드가 할당된 리소스에 대한 읽기 및 쓰기 작업 중에 스레드와 작업을 동기화해야 합니다.
리소스에 액세스할 때 다른 스레드가 변경할 수 있고 최신 정보를 얻을 수 있도록 최신 데이터를 가지고 있는 것이 중요합니다. 은행 계좌를 예로 들어도 돈이 들어오기 전까지는 사용할 수 없기 때문에 항상 최신 데이터를 유지하는 것이 중요합니다. Java에는 스레드를 동기화하고 관리하기 위한 특수 클래스가 있습니다.
스레드 개체
그것은 모두 메인(메인) 스레드로 시작합니다. 즉, 최소한 프로그램에는 이미 하나의 실행 중인 스레드가 있습니다. 메인 스레드는 Callable 또는 Runnable 을 사용하여 다른 스레드를 생성할 수 있습니다 . 생성은 반환 결과에서만 다릅니다. Runnable은 결과를 반환하지 않으며 확인된 예외를 throw할 수 없습니다. 따라서 효율적인 파일 작업을 구축할 수 있는 좋은 기회를 얻을 수 있지만 이는 매우 위험하므로 주의해야 합니다.
별도의 CPU 코어에서 스레드 실행을 예약하는 것도 가능합니다. 시스템은 스레드 사이를 쉽게 이동하고 올바른 설정으로 특정 스레드를 실행할 수 있습니다. 즉, 데이터를 읽는 스레드가 먼저 실행되고 데이터가 있는 즉시 유효성 검사를 담당하는 스레드로 전달합니다. 그런 다음 스레드에 전달하여 일부 비즈니스 로직을 실행하고 새 스레드가 다시 작성합니다. 이러한 상황에서 4개의 스레드가 차례로 데이터를 처리하고 모든 것이 하나의 스레드보다 빠르게 작동합니다. 이러한 각 스트림은 기본 OS 스트림으로 변환되지만 변환 방법은 JVM 구현에 따라 다릅니다.
Thread 클래스 는 스레드를 만들고 작업하는 데 사용됩니다. 표준 제어 메커니즘과 java.util.concurrent 의 클래스 및 컬렉션과 같은 추상 메커니즘이 있습니다 .
Java의 스레드 동기화
통신은 개체에 대한 액세스를 공유하여 제공됩니다. 이것은 매우 효과적이지만 동시에 작업할 때 실수하기가 매우 쉽습니다. 오류는 스레드 간섭 - 다른 스레드가 스레드를 방해하는 경우와 메모리 일관성 오류 - 메모리 일관성의 두 가지 경우에 발생합니다. 이러한 오류를 해결하고 방지하기 위해 다양한 동기화 방법이 있습니다.
Java의 스레드 동기화는 모니터에 의해 처리되며, 이는 한 번에 하나의 스레드만 동일한 모니터에 의해 보호되는 코드 블록을 실행할 수 있도록 하는 높은 수준의 메커니즘입니다. 모니터의 동작은 잠금 측면에서 고려됩니다. 하나의 모니터 - 하나의 잠금.
동기화에는 주의해야 할 몇 가지 중요한 사항이 있습니다. 첫 번째 요점은 상호 배제입니다. 하나의 스레드만 모니터를 소유할 수 있으므로 모니터에서의 동기화는 한 스레드가 모니터에 의해 보호되는 동기화된 블록에 들어가면 다른 스레드는 모니터에 의해 보호되는 블록에 들어갈 수 없음을 의미합니다. 첫 번째 스레드는 동기화된 블록을 종료합니다. 즉, 여러 스레드가 동시에 동일한 동기화 블록에 액세스할 수 없습니다.
그러나 동기화는 상호 배타만이 아닙니다. 동기화는 동기화된 블록 이전 또는 내에서 메모리에 기록된 데이터가 동일한 모니터에서 동기화된 다른 스레드에 표시되도록 합니다. 블록을 종료한 후 모니터를 해제하면 다른 스레드가 모니터를 잡고 이 코드 블록 실행을 시작할 수 있습니다.
새 스레드가 모니터를 캡처하면 해당 코드 블록에 대한 액세스 권한과 실행 능력을 얻게 되며, 그 시점에서 변수는 메인 메모리에서 로드됩니다. 그러면 모니터의 이전 릴리스에서 볼 수 있는 모든 항목을 볼 수 있습니다.
필드가 volatile로 선언되어 있거나(long과 double에서는 이것이 중요합니다) 필드에 대한 모든 액세스가 같은 잠금으로 보호되는 경우, 필드에 대한 개별 읽기 또는 쓰기는 원자적으로 수행됩니다. 동기화가 없으면 재정렬(reordering) 효과가 나타날 수 있습니다. 잘못 동기화된 프로그램에서는 한 스레드가 다른 스레드가 만든 변경 사항을 예상치 못한 순서로 볼 수 있습니다.
암묵적으로 잠금을 획득하는 동기화된 블록이나 메서드에 진입하거나 명시적으로 잠금을 획득해야만 스레드의 상호 배제 및 동기화 효과, 즉 스레드의 올바른 작동이 달성됩니다. 아래에서 이에 대해 이야기하겠습니다. 두 작업 방식 모두 메모리에 영향을 미치며 휘발성 변수 작업을 잊지 않는 것이 중요합니다 .
Java의 휘발성 필드
volatile 키워드는 가시성 문제를 해결합니다. 한 스레드가 volatile 필드에 값을 썼다면, 이후에 그 필드를 읽는 다른 모든 스레드는 오래된 복사본이 아니라 새 값을 보게 됩니다.
메모리에 대한 효과 측면에서 volatile 필드에 쓰는 것은 모니터를 해제하는 것과 비슷하고, 읽는 것은 모니터를 획득하는 것과 비슷합니다. 스레드 A가 volatile 필드에 쓰기 전에 기록한 모든 것은, 스레드 B가 이 필드에서 기록된 값을 읽었다면 스레드 B에게 반드시 보입니다. 이 관계를 happens-before("먼저 일어남")라고 합니다.
volatile 필드에 대한 개별 읽기 또는 쓰기는 long과 double의 경우에도 원자적입니다. 하지만 count++(읽기, 증가, 쓰기) 같은 복합 연산은 원자적이지 않습니다. 단계 사이에 다른 스레드가 끼어들 수 있고, 증가분의 일부가 사라집니다. volatile은 상호 배제를 제공하지 않습니다. 복합 연산을 원자적으로 실행하려면 synchronized, Lock 또는 AtomicInteger, AtomicLong 등의 클래스가 필요합니다.
자바 동시
매우 효율적인 다중 스레드 애플리케이션을 만들고 싶다면 java.util.concurrent 패키지 에 있는 JavaConcurrent 라이브러리의 클래스를 사용해야 합니다 .
라이브러리는 방대하고 기능이 다양하므로 내부에 무엇이 있는지 살펴보고 일부 모듈로 나누어 보겠습니다.
동시 컬렉션은 다중 스레드 환경에서 작업하기 위한 컬렉션 집합입니다. 전체 컬렉션에 대한 액세스를 차단하는 기본 래퍼 Collections.synchronizedList 대신 데이터 세그먼트에 잠금이 사용되거나 대기 없는 알고리즘이 데이터를 병렬로 읽는 데 사용됩니다.
대기열 - 다중 스레드 환경에서 작업하기 위한 비차단 및 차단 대기열입니다. 비차단 대기열은 스레드를 차단하지 않고 속도와 작업에 중점을 둡니다. 블로킹 대기열은 생산자 또는 소비자 스레드를 "느리게" 해야 할 때 작업에 적합합니다. 예를 들어, 일부 조건이 충족되지 않는 상황에서 대기열이 비어 있거나 가득 차 있거나 무료 소비자 'a 가 없습니다.
동기화 프로그램은 스레드 동기화를 위한 유틸리티 유틸리티입니다. 그것들은 "병렬" 컴퓨팅에서 강력한 무기입니다.
Executors 는 스레드 풀을 보다 편리하고 쉽게 생성할 수 있는 프레임워크로, 결과를 얻는 비동기 작업의 스케줄링을 쉽게 설정할 수 있습니다.
잠금은 기본 synchronized , wait , notify , notifyAll 에 비해 많은 유연한 스레드 동기화 메커니즘입니다 .
원자는 프리미티브 및 참조에 대한 원자 연산을 지원할 수 있는 클래스입니다.
GO TO FULL VERSION