자바 에서 자주 사용 하 는 원자 류 를 상세 하 게 정리 하 다.

9269 단어 Java상용원자 류
원자 류
자바 에 서 는 원자 류 를 제공 하고 원자 류 는 변 수 를 포장 하 며 변 수 를 원자 적 으로 조작 하 는 일련의 방법 을 제공 했다.우 리 는 다 중 스 레 드 환경 에서 이런 원자 류 를 조작 할 때 자 물 쇠 를 추가 하지 않 아 도 되 고 병발 프로 그래 밍 의 개발 을 크게 간소화 했다.
2.원자 류 의 밑바닥 실현
현재 자바 에서 제공 하 는 원자 류 의 대부분 밑바닥 은 CAS 자물쇠(CompareAndSet 자선 자물쇠)를 사용 하고 있다.예 를 들 어 AtomicInteger,AtomicLong 등 이다.세그먼트 잠 금+CAS 잠 금 을 사용 한 원자 류,예 를 들 어 LongAdder 등 도 있다.
3.자주 사용 하 는 원자 류
3.1 AtomicInteger 와 AtomicLong
AtomicInteger 와 AtomicLong 의 밑바닥 실현 은 용법 과 기본적으로 같다.다른 점 은 AtomicInteger 가 Integer 형 변 수 를 포 장 했 고 AtomicLong 은 Long 형 변 수 를 포 장 했 기 때문이다.
AtomicInteger 와 AtomicLong 의 밑바닥 실현 은 모두 CAS 자 물 쇠 를 사용 했다.

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author IT00ZYQ
 * @date 2021/5/24 15:33
 **/
public class T13_AtomicInteger {
    private static AtomicInteger atomicInteger = new AtomicInteger();
    private static AtomicLong atomicLong = new AtomicLong();
    private static Integer integer = 0;
    private static Long lon = 0L;
    public static void main(String[] args) {

        //   10   ,   atomicInteger、atomicLong、integer、lon  1000   1   
        //          ,       = 10 * 1000 = 10000
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 1; j <= 1000; j++) {
                    atomicInteger.incrementAndGet();
                    atomicLong.incrementAndGet();
                    integer ++;
                    lon ++;
                }
            });
        }

        //     
        for (Thread thread : threads) {
            thread.start();
        }

        //   10       
        try {
            for (Thread thread : threads) {
                thread.join();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("AtomicInteger   :" + atomicInteger);
        System.out.println("AtomicLong   :" + atomicLong);
        System.out.println("Integer   :" + integer);
        System.out.println("Long   :" + lon);
    }
}
실행 결과:
AtomicInteger 결과:10000
AtomicLong 결과:10000
Integer 결과:4880
Long 결과:4350
Process finished with exit code 0
여러 차례 실 행 된 원자 류 AtomicInteger 와 AtomicLong 은 매번 정확 한 결 과 를 얻 을 수 있 지만 비 원자 류 Integer 와 Long 은 일반적으로 10000 에 이 르 지 못 하고 매번 결과 도 다 를 수 있 습 니 다.
3.2 LongAdder
LongAdder 의 밑바닥 은 분 단 자 물 쇠 를 사 용 했 고 각 단락 은 CAS 자 물 쇠 를 사 용 했 기 때문에 LongAdder 의 밑바닥 은 분 단 자물쇠+CAS 자 물 쇠 를 실현 했다.
위의 프로그램 에 LongAdder 변 수 를 추가 하여 테스트 합 니 다.

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author IT00ZYQ
 * @date 2021/5/24 15:33
 **/
public class T13_AtomicInteger {
    private static AtomicInteger atomicInteger = new AtomicInteger();
    private static AtomicLong atomicLong = new AtomicLong();
    private static LongAdder longAdder = new LongAdder();
    private static Integer integer = 0;
    private static Long lon = 0L;
    public static void main(String[] args) {

        //   10   ,   atomicInteger、atomicLong、integer、lon  1000   1   
        //          ,       = 10 * 1000 = 10000
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 1; j <= 1000; j++) {
                    atomicInteger.incrementAndGet();
                    atomicLong.incrementAndGet();
                    integer ++;
                    lon ++;
                    longAdder.increment();
                }
            });
        }

        //     
        for (Thread thread : threads) {
            thread.start();
        }

        //   10       
        try {
            for (Thread thread : threads) {
                thread.join();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("AtomicInteger   :" + atomicInteger);
        System.out.println("AtomicLong   :" + atomicLong);
        System.out.println("Integer   :" + integer);
        System.out.println("Long   :" + lon);
        System.out.println("LongAdder   :" + longAdder);
    }
}
실행 결과:
AtomicInteger 결과:10000
AtomicLong 결과:10000
Integer 결과:6871
Long 결과:6518
LongAdder 결과:10000
Process finished with exit code 0
LongAdder 류 도 결 과 를 정확하게 출력 할 수 있다.
4.원자 류 의 성능 테스트
4.1 테스트 프로그램

package juc;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author IT00ZYQ
 * @date 2021/5/24 15:51
 **/
public class T14_AtomicClassPerformance {
    private static AtomicLong atomicLong = new AtomicLong();
    private static LongAdder longAdder = new LongAdder();
    /**
     *    
     */
    private static final int THREAD_COUNT = 100;
    /**
     *           
     */
    private static final int OPERATION_COUNT = 10000;

    public static void main(String[] args) {
        Thread[] threads = new Thread[THREAD_COUNT];

        
        //    AtomicLong       
        for (int i = 0; i < THREAD_COUNT; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < OPERATION_COUNT; j++) {
                    atomicLong.incrementAndGet();
                }
            });
        }

        long start1 = System.currentTimeMillis();
        //     
        for (Thread thread : threads) {
            thread.start();
        }

        //         
        try {
            for (Thread thread : threads) {
                thread.join();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end1 = System.currentTimeMillis();


        //    LongAdder       
        for (int i = 0; i < THREAD_COUNT; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < OPERATION_COUNT; j++) {
                    longAdder.increment();
                }
            });
        }

        long start2 = System.currentTimeMillis();
        //     
        for (Thread thread : threads) {
            thread.start();
        }

        //         
        try {
            for (Thread thread : threads) {
                thread.join();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end2 = System.currentTimeMillis();

        System.out.println("AtomicLong    : " + (end1 - start1) + "ms,     :" + atomicLong);
        System.out.println("LongAdder    : " + (end2 - start2) + "ms,     :" + longAdder);
    }

}
4.2 테스트 결과
4.567914 시의 운행 결과
AtomicLong 실행 시간:40ms,실행 결과:100000
LongAdder 운행 시간:57ms,운행 결과:100000
Process finished with exit code 0
4.567914 시의 운행 결과
AtomicLong 실행 시간:108 ms,실행 결과:1000000
LongAdder 운행 시간:85ms,운행 결과:1000000
Process finished with exit code 0
4.567914 시의 운행 결과
AtomicLong 운행 시간:6909 ms,운행 결과:100000000
LongAdder 운행 시간:468 ms,운행 결과:100000000
Process finished with exit code 0
4.567914 시의 운행 결과
AtomicLong 운행 시간:788 ms,운행 결과:10000000
LongAdder 운행 시간:162 ms,운행 결과 10000000
Process finished with exit code 0
4.3 결과 분석
4THREAD_COUNT = 100, OPERATION_COUNT = 1000충분 한 시간 동안 AtomicInteger 의 성능 은 LongAdder 보다 약간 높 을 것 이다.4.567914.증가 함 에 따라 LongAdder 의 성능 이 더욱 높 고 4.567914.충분 할 때 LongAdder 의 성능 은 AtomicInteger 보다 훨씬 높다.
4.4 밑바닥 실현 분석
  • AtomicLong 의 원자 성 자체 증가 조작 은 CAS 를 통 해 이 루어 진 것 이다.경쟁 스 레 드 수가 적 고 모든 스 레 드 의 운행 에 소요 되 는 시간 이 비교적 짧 은 상황 에서 이렇게 하 는 것 이 적당 하 다.그러나 라인 경쟁 이 치열 하면 대량의 라인 이 제자리 에서 맴 돌 고 끊임없이 값 을 수정 하려 고 시도 하지만 값 이 수 정 된 것 을 발견 하고 계속 자전 한다.이렇게 해서 대량의 CPU 자원 을 낭비 했다
  • 4.567917.LongAdder 는 경쟁 이 치열 할 때 여러 개의 스 레 드 가 계속 자전 하여 값 을 수정 하지 않 고 세그먼트 의 사상 을 사용 했다.각 스 레 드 는 자신 이 대응 하 는 Cell[]배열 의 특정한 배열 대상 요소 에 분산 되 고 모두 가 하 나 를 공유 하지 않 으 며 서로 다른 스 레 드 를 서로 다른 Cell 에 대응 하여 수정 하여 임계 자원 에 대한 경쟁 을 낮 출 수 있다.본질 적 으로 공간 으로 시간 을 바 꾸 는 것 이다자바 에서 자주 사용 하 는 원자 류 를 상세 하 게 정리 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 에서 자주 사용 하 는 원자 류 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기