JavaRush /Java Blog /Random-KO /레벨 26. 레벨 주제에 대한 인터뷰 질문에 대한 답변입니다. 2부. 질문 6-9, 11-12
zor07
레벨 31
Санкт-Петербург

레벨 26. 레벨 주제에 대한 인터뷰 질문에 대한 답변입니다. 2부. 질문 6-9, 11-12

Random-KO 그룹에 게시되었습니다
레벨 26. 레벨 주제에 대한 인터뷰 질문에 대한 답변입니다.  2부. 질문 6-9, 11-12 - 1

6. 칸카렌지란 무엇인가요?

동시성은 여러 스레드에서 작업하도록 최적화된 특수 클래스를 포함하는 Java의 클래스 라이브러리입니다. 이러한 클래스는 패키지로 수집됩니다 java.util.concurrent. 기능에 따라 다음과 같이 개략적으로 나눌 수 있습니다. 레벨 26. 레벨 주제에 대한 인터뷰 질문에 대한 답변입니다.  2부. 질문 6-9, 11-12 - 2동시 컬렉션java.util - 패키지 의 표준 범용 컬렉션보다 다중 스레드 환경에서 더 효율적으로 작동하는 컬렉션 집합입니다 . 전체 컬렉션에 대한 액세스를 차단하는 기본 래퍼 대신 Collections.synchronizedList데이터 세그먼트에 대한 잠금이 사용되거나 대기 없는 알고리즘을 사용하여 데이터의 병렬 읽기에 작업이 최적화됩니다. 대기열 - 멀티스레딩을 지원하는 비차단 및 차단 대기열입니다. 비차단 대기열은 스레드를 차단하지 않고 속도와 작업을 수행하도록 설계되었습니다. 차단 대기열은 일부 조건이 충족되지 않는 경우(예: 대기열이 비어 있거나 오버플로되거나 사용 가능한 “소비자”가 없는 경우) “생산자” 또는 “소비자” 스레드를 “느리게” 해야 할 때 사용됩니다. 동기화 장치는 스레드 동기화를 위한 보조 유틸리티입니다. 이는 "병렬" 컴퓨팅의 강력한 무기입니다. 실행자 - 스레드 풀 생성, 비동기 작업 예약 및 결과 획득을 위한 탁월한 프레임워크가 포함되어 있습니다. 잠금 - 기본 동기화 메커니즘 synchronized에 비해 대체적이고 보다 유연한 스레드 동기화 메커니즘을 나타냅니다 . Atomics - 기본 요소 및 참조에 대한 원자적 작업을 지원하는 클래스입니다. 원천:waitnotifynotifyAll

7. Kankarensi의 어떤 수업을 알고 있나요?

이 질문에 대한 대답은 이 기사 에 완벽하게 설명되어 있습니다 . 여기에서 모든 내용을 재인쇄하는 것이 의미가 없기 때문에 제가 잠깐 알게 된 영광을 누렸던 수업에 대해서만 설명하겠습니다. ConcurrentHashMap<K, V> - Hashtable및 블록 synhronized과 달리 HashMap데이터는 키 해시로 나누어진 세그먼트 형태로 표시됩니다. 결과적으로 데이터는 단일 개체가 아닌 세그먼트를 통해 액세스됩니다. 또한 반복자는 특정 기간 동안의 데이터를 나타내며 ConcurrentModificationException. AtomicBoolean, AtomicInteger, AtomicLong, AtomicIntegerArray, AtomicLongArray - 클래스에서 하나의 간단한 유형 변수에 대한 액세스를 동기화해야 하는 경우 어떻게 해야 합니까 int? synchronized원자 연산을 사용하는 경우 및 와 함께 구문을 사용할 수 있습니다 set/get. volatile하지만 새로운 클래스를 사용하면 훨씬 더 나은 결과를 얻을 수 있습니다 Atomic*. CAS를 사용하므로 이러한 클래스를 사용한 작업은 synchronized/volatile. 또한, 주어진 양만큼 원자를 추가하는 방법과 증가/감소 방법이 있습니다.

8. ConcurrentHashMap 클래스는 어떻게 작동하나요?

Java 개발자는 도입 당시 ConcurrentHashMap다음과 같은 해시 맵 구현이 필요했습니다.
  • 스레드 안전성
  • 테이블에 액세스하는 동안 전체 테이블에 대한 잠금이 없습니다.
  • 읽기 작업을 수행할 때 테이블 잠금이 없는 것이 바람직합니다.
주요 구현 아이디어는 ConcurrentHashMap다음과 같습니다.
  1. 지도 요소

    요소와 달리 in은 HashMap로 선언됩니다 . 이는 JMM 의 변경으로 인해 중요한 기능이기도 합니다 .EntryConcurrentHashMapvolatile

    static final class HashEntry<K, V> {
        final K key;
        final int hash;
        volatile V value;
        final HashEntry<K, V> next;
    
        HashEntry(K key, int hash, HashEntry<K, V> next, V value) {
            this .key = key;
            this .hash = hash;
            this .next = next;
            this .value = value;
         }
    
        @SuppressWarnings("unchecked")
        static final <K, V> HashEntry<K, V>[] newArray(int i) {
            return new HashEntry[i];
        }
    }
  2. 해시 함수

    ConcurrentHashMap향상된 해싱 함수도 사용됩니다.

    HashMapJDK 1.2 에서는 어땠는지 상기시켜 드리겠습니다 .

    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    ConcurrentHashMap JDK 1.5 버전:

    private static int hash(int h) {
        h += (h << 15) ^ 0xffffcd7d;
        h ^= (h >>> 10);
        h += (h << 3);
        h ^= (h >>> 6);
        h += (h << 2) + (h << 14);
        return h ^ (h >>> 16);
    }

    해시 함수를 더 복잡하게 만들 필요가 있는 이유는 무엇입니까? 해시 맵의 테이블 길이는 2의 거듭제곱으로 결정됩니다. 이진 표현이 낮은 위치와 높은 위치에서 다르지 않은 해시 코드의 경우 충돌이 발생합니다. 해시 함수의 복잡성을 높이면 이 문제가 해결되어 지도에서 충돌 가능성이 줄어듭니다.

  3. 세그먼트

    맵은 N개의 서로 다른 세그먼트(기본적으로 16개, 최대값은 16비트일 수 있으며 2의 거듭제곱)로 나뉩니다. 각 세그먼트는 스레드로부터 안전한 맵 요소 테이블입니다. 세그먼트 수를 늘리면 수정 작업이 여러 세그먼트에 걸쳐 수행되도록 하여 런타임 시 차단 가능성이 줄어듭니다.

  4. 동시성 수준

    이 매개변수는 메모리 카드 사용량과 카드의 세그먼트 수에 영향을 미칩니다.

    세그먼트 수는 concurrencyLevel보다 큰 2의 가장 가까운 거듭제곱으로 선택됩니다. concurrencyLevel을 낮추면 쓰기 시 스레드가 맵 세그먼트를 차단할 가능성이 높아집니다. 지표를 과대평가하면 메모리가 비효율적으로 사용됩니다. 하나의 스레드만 맵을 수정하고 나머지는 읽는 경우 값 1을 사용하는 것이 좋습니다.

  5. 따라서 주요 장점 및 구현 기능은 다음과 같습니다 ConcurrentHashMap.

    • 지도에는 다음과 유사한 hashmap상호작용 인터페이스가 있습니다.
    • 읽기 작업에는 잠금이 필요하지 않으며 병렬로 수행됩니다.
    • 쓰기 작업은 종종 차단 없이 병렬로 수행될 수도 있습니다.
    • 생성 시 필요한 항목이 표시되며 concurrencyLevel, 통계를 읽고 쓰는 방식으로 결정됩니다.
    • value지도 요소에는 다음과 같이 선언된 값이 있습니다.volatile
    출처: ConcurrentHashMap 작동 방식

9. Lock 클래스란 무엇입니까?

공유 리소스에 대한 액세스를 제어하기 위해 동기화 연산자 대신 잠금을 사용할 수 있습니다. 잠금 기능은 에 패키지되어 있습니다 java.util.concurrent.locks. 먼저 스레드는 공유 리소스에 액세스하려고 시도합니다. 비어 있으면 스레드에 잠금이 설정됩니다. 작업이 완료되면 공유 리소스에 대한 잠금이 해제됩니다. 리소스가 사용 가능하지 않고 이미 잠금이 설정된 경우 스레드는 이 잠금이 해제될 때까지 기다립니다. Lock잠금 클래스는 다음 메서드를 정의하는 인터페이스를 구현합니다 .
  • void lock():잠금이 획득될 때까지 기다립니다.
  • boolean tryLock():잠금을 획득하려고 시도하며, 잠금이 획득되면 true 를 반환합니다 . 잠금을 획득하지 못한 경우 false 를 반환합니다 . 이 방법과 달리 lock()잠금을 사용할 수 없는 경우 잠금 획득을 기다리지 않습니다.
  • void unlock():자물쇠를 제거한다
  • Condition newCondition():Condition현재 잠금과 연관된 객체를 반환합니다.
일반적인 경우 잠금 구성은 매우 간단합니다. 잠금을 얻으려면 메서드를 호출 하고, 공유 리소스 작업을 마친 후 잠금을 해제하는 lock()메서드를 호출합니다 . unlock()개체를 사용 Condition하면 차단을 관리할 수 있습니다. 일반적으로 잠금 작업에는 ReentrantLock패키지의 클래스가 사용되며 java.util.concurrent.locks.이 클래스는 인터페이스를 구현합니다 Lock. 예를 들어 작은 프로그램을 사용하여 Java Lock API를 사용하는 방법을 살펴보겠습니다. 따라서 Resource스레드로부터 안전한 메소드와 스레드 안전성이 필요하지 않은 메소드가 있는 클래스가 있다고 가정해 보겠습니다.
public class Resource {

    public void doSomething(){
        // пусть здесь происходит работа с базой данных
    }

    public void doLogging(){
        // потокобезопасность для логгирования нам не требуется
    }
}
Runnable이제 인터페이스를 구현 하고 클래스 메소드를 사용하는 클래스를 살펴보겠습니다 Resource.
public class SynchronizedLockExample implements Runnable{

    // экземпляр класса Resource для работы с методами
    private Resource resource;

    public SynchronizedLockExample(Resource r){
        this.resource = r;
    }

    @Override
    public void run() {
        synchronized (resource) {
            resource.doSomething();
        }
        resource.doLogging();
    }
}
이제 .dll 대신 Lock API를 사용하여 위 프로그램을 다시 작성해 보겠습니다 synchronized.
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// класс для работы с Lock API. Переписан с приведенной выше программы,
// но уже без использования ключевого слова synchronized
public class ConcurrencyLockExample implements Runnable{

    private Resource resource;
    private Lock lock;

    public ConcurrencyLockExample(Resource r){
        this.resource = r;
        this.lock = new ReentrantLock();
    }

    @Override
    public void run() {
        try {
            // лочим на 10 секунд
            if(lock.tryLock(10, TimeUnit.SECONDS)){
            resource.doSomething();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            //убираем лок
            lock.unlock();
        }
        // Для логгирования не требуется потокобезопасность
        resource.doLogging();
    }

}
프로그램에서 볼 수 있듯이 tryLock()스레드가 특정 시간 동안만 기다리는지 확인하기 위해 메서드를 사용합니다. 객체에 대한 잠금을 얻지 못하면 단순히 기록하고 종료됩니다. 또 다른 중요한 점. 메서드 에서 예외가 발생 try-finally하더라도 잠금이 해제되도록 하려면 블록을 사용해야 합니다 . 출처:doSomething()

11. 뮤텍스란 무엇입니까?

뮤텍스 는 스레드/프로세스를 동기화하기 위한 특수 개체입니다. 바쁨과 한가함의 두 가지 상태를 취할 수 있습니다. 단순화하기 위해 뮤텍스는 사용 중(true)과 사용 가능(false)의 두 가지 값을 취하는 부울 변수입니다. 스레드가 개체의 독점 소유권을 원하면 해당 뮤텍스를 사용 중으로 표시하고 작업이 완료되면 해당 뮤텍스를 사용 가능으로 표시합니다. 뮤텍스는 Java의 모든 객체에 연결됩니다. Java 시스템만이 뮤텍스에 직접 액세스할 수 있습니다. 프로그래머에게는 숨겨져 있습니다.

12. 모니터란 무엇입니까?

모니터는 올바른 작동을 보장하는 뮤텍스에 대한 추가 기능인 특수 메커니즘(코드 조각)입니다. 결국 객체가 사용 중임을 표시하는 것만으로는 충분하지 않으며 다른 스레드가 사용 중인 객체를 사용하려고 시도하지 않도록 해야 합니다. Java에서는 키워드를 사용하여 모니터를 구현합니다 synchronized. 동기화된 블록을 작성할 때 Java 컴파일러는 이를 세 가지 코드 조각으로 대체합니다.
  1. 블록 시작 부분에는 synchronized뮤텍스를 사용 중으로 표시하는 코드가 추가됩니다.
  2. 블록 끝에는 synchronized뮤텍스를 사용 가능으로 표시하는 코드가 추가됩니다.
  3. 블록 앞에 synchronized뮤텍스가 사용 중인지 확인하는 코드가 추가되고 스레드는 뮤텍스가 해제될 때까지 기다려야 합니다.
1 부
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION