자바 Atomic 클래스 및 스 레 드 동기 화 새로운 메커니즘 원리 분석

1.왜 Atomic 류 를 사용 합 니까?
다음 애플 릿 을 보 세 요.아 날로 그 계수,10 개의 스 레 드 를 만 들 고 이 int count=0 에 공동으로 접근 합 니 다.모든 스 레 드 는 count 에 10000 을 추가 합 니 다.이 럴 때 자 물 쇠 를 추가 해 야 합 니 다.자 물 쇠 를 추가 하지 않 으 면 스 레 드 안전 문제 가 발생 할 수 있 습 니 다.그러나 Atomic Integer 를 사용 한 후에 자 물 쇠 를 추가 하 는 작업 을 하지 않 아 도 됩 니 다.Atomic Integer 내부 에서 CAS 작업 을 사 용 했 기 때문에 자물쇠 없 이 위로 점점 증가 합 니 다.어떤 사람 이 자물쇠 없 는 작업 이 나타 날 지 물 어 볼 것 입 니 다.답 은 하나 밖 에 없습니다.그것 이 빠 른 것 입 니 다.
다음은 AtomicInteger 의 사용 방법 입 니 다.

package com.example.demo.threaddemo.juc_008;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author D-L
 * @Classname T01_AtomicInteger
 * @Version 1.0
 * @Description   AtomicInteger   synchronized
 * @Date 2020/7/22
 */
public class T01_AtomicInteger {
//  int count = 0;
   AtomicInteger count = new AtomicInteger(0);

  public /**synchronized*/ void m(){
    for (int i = 0; i < 10000; i++) {
//      count++;
      count.incrementAndGet();
    }
  }

  public static void main(String[] args) {
    T01_AtomicInteger t = new T01_AtomicInteger();
    List<Thread> threads = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
      threads.add(new Thread(t::m ,"Thread" + i));
    }
    threads.forEach(o -> o.start());
    threads.forEach(o ->{
      try {
        o.join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    });
    /* for (int i = 0; i < 10; i++) {
      new Thread(t::m ,"Thread"+i).start();
    }
    try {
      TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }*/
    System.out.println(t.count);
  }
}
2.Atomic 류,synchronized,LongAdder 의 효율 검증 및 분석
여러 개의 스 레 드 를 모 의 하여 하나의 수 를 증가 시 키 고 다 중 스 레 드 가 하나의 공유 변 수 를 증가 시 키 는 방법 은 대략 세 가지 가 있다.그들의 효율 을 검증 해 보 세 요.여기 서 거 친 테스트 를 하면 기본적으로 문 제 를 설명 할 수 있 고 구체 적 인 상황 은 실제 상황 에 따라 야 합 니 다.
첫 번 째:long count=0 사용 하기;자 물 쇠 를 넣 어 실현 하기;
두 번 째:AtomicLong 류 를 사용 하여 실현 합 니 다.
세 번 째:LongAdder 를 사용 하여 실현 합 니 다.

package com.example.demo.threaddemo.juc_008;

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

/**
 * @author D-L
 * @Classname T02_AtomicVsSyncVsLongAdder
 * @Version 1.0
 * @Description   Atomic  synchronized LongAdder  
 * @Date 2020/7/22
 */
public class T02_AtomicVsSyncVsLongAdder {
  static AtomicLong count1 = new AtomicLong(0L);
  static Long count2 = 0L;
  static LongAdder count3 = new LongAdder();

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

    /*-----------------------------------Atomic -----------------------------------*/
    for (int i = 0; i < threads.length; i++) {
      threads[i] = new Thread(() ->{
        for (int j = 0; j < 100000; j++) {
          count1.incrementAndGet();
        }
      });
    }
    long start = System.currentTimeMillis();
    for (Thread t : threads) t.start();
    for (Thread t : threads) t.join();
    long end = System.currentTimeMillis();
    System.out.println("Atomic:" + count1.get() +"-----time:" +(end - start));

    /*----------------------------------synchronized---------------------------------*/
    Object lock = new Object();
    for (int i = 0; i < threads.length; i++) {
      threads[i] = new Thread(new Runnable() {
        @Override
        public void run() {
          for (int j = 0; j < 100000; j++) {
            synchronized (lock) {
              count2++;
            }
          }
        }
      });
    }
    long start2 = System.currentTimeMillis();
    for (Thread t : threads) t.start();
    for (Thread t : threads) t.join();
    long end2 = System.currentTimeMillis();
    System.out.println("synchronized:" + count1.get() +"-----time:" +(end2 - start2));

    /*-------------------------------------LongAdder----------------------------------*/
    for (int i = 0; i < threads.length; i++) {
      threads[i] = new Thread(() ->{
        for (int j = 0; j < 100000; j++) {
          count3.increment();
        }
      });
    }
    long start3 = System.currentTimeMillis();
    for (Thread t : threads) t.start();
    for (Thread t : threads) t.join();
    long end3 = System.currentTimeMillis();
    System.out.println("LongAdder:" + count1.get() +"-----time:" +(end3 - start3));
  }
}
 /*----------------------------------    ---------------------------------*/
Atomic:100000000-----time:2096synchronized:100000000-----time:5765LongAdder:100000000-----time:515
이상 의 결 과 를 보면 병발 량 이 어느 정도 운행 효율 에 이 르 렀 다.LongAdder>AtomicLong>synchronized;이것 은 아직 대략적인 테스트 일 뿐 구체 적 으로 사용 하려 면 실제 상황 에 따라 야 한다.
왜 AtomicLong 의 효율 은 synchronized 의 효율 보다 높 습 니까?
AtomicLong 의 바 텀 은 CAS 작업(잠 금 없 는 최적화)을 사용 하 는데 synchronized 는 바 텀 이 최적화 되 었 지만 병발 량 이 일정한 층 도 에 이 르 렀 고 자물쇠 의 팽창 이 존재 하 며 결국은 중량급 자물쇠 가 될 것 이 며 운영 체제 에 잠 금 자원 을 신청 해 야 하기 때문에 synchronized 의 효율 이 느 리 고 합 리 적 입 니 다.
왜 LongAdder 의 효율 은 AtomicLong 보다 높 습 니까?
롱 애 더 는 세그먼트 잠 금 이라는 개념 을 사용 해 아 토 믹 롱 보다 효율 적 이기 때문이다.

세그먼트 잠 금 은 한 배열 로 스 레 드 를 여러 그룹 으로 나 눈 다음 에 운행 이 끝 난 후에 결 과 를 누적 하 는 것 을 의미한다.예 를 들 어 1000 개의 스 레 드 가 있 고 배열 의 길 이 는 4 이다.그러면 0-250 개 를 배열 의 0 위 에 놓 고 이런 식 으로 유추 한 다음 에 네 개의 배열 에서 스 레 드 의 계산 결 과 를 누적 하면 어느 정도 시간 을 절약 하여 효율 을 높 일 수 있다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기