자바 병렬 프로 그래 밍 및 동기 화 방법

직렬 프로 그래 밍 에 비해 병렬 프로 그래 밍 은 다음 과 같은 세 가지 주요 목표 가 있 습 니 다.
  • 성능 - 현재 CPU 성능 이 병목 에 부 딪 혔 기 때문에 단일 스 레 드 프로 그래 밍 을 사용 하면 다 핵 CPU 의 성능 을 발휘 할 수 없습니다
  • 생산 율 - 병행 소프트웨어 를 만 드 는 생산 율 향상
  • 유 니 버 설 - 개발 병행 프로그램 은 높 은 비용 이 필요 하고 더욱 통용 되 는 병행 프로그램 은 원 가 를 효과적으로 낮 출 수 있다.그러나 유 니 버 설 성 은 더 큰 성능 손실 과 생산성 손실 을 가 져 올 수 있다.현재 유행 하 는 내 가 아 는 병렬 프로 그래 밍 환경 을 참고 하 세 요.
  • 자바 의 프로 그래 밍 환경 은 타고 난 다 중 스 레 드 능력 을 제공 합 니 다. 병렬 프로 그래 밍 을 실현 하려 면 다음 과 같은 문 제 를 해결 해 야 합 니 다.
    1. 단일 스 레 드 의 순서 프로 세 스 를 지정 합 니 다. 단일 스 레 드 는 모든 프로 세 스 의 자원 에 접근 할 수 있 습 니 다.
    2. 스 레 드 가 방문 자원 을 어떻게 조율 하 는 지 이런 조 화 는 매우 많은 동기 화 체제 가 서로 다른 병행 언어 와 환경 을 제공 함으로써 실시 하 는 것 이다. 이 는 메시지 전달, 잠 금, 사무, 인용 계수, 표시 시간, 공유 원자 변수 와 데이터 소유권 을 포함한다.전통 적 인 프로 그래 밍 을 바탕 으로 자물쇠, 자물쇠 와 사 무 를 되 돌려 줍 니 다.
    실현 방법 1: jdk 5 에 추 가 된 CountDownlatch (카운터 에 해당 하 는) 대상 을 통 해 이 루어 집 니 다. 기본 적 인 사 고 는 하나의 스 레 드 를 실행 할 때마다 CountDownlatch. countDown () 방법 으로 계산 기 를 1 로 줄 이 고 메 인 스 레 드 는 CountDownlatch. awat () 를 0 으로 줄 이 는 것 입 니 다.
    구체 적 인 코드 는 참고 할 수 있다.
    http://blog.csdn.net/wangmuming/article/details/19832865

    실현 방법 2:
    ExecutorService executor = Executors. newFixed ThreadPool (int threadNum) 을 통 해 스 레 드 풀 을 만 듭 니 다.
    List > result = executor. invokeAll (Collection tasks >) 을 호출 하여 스 레 드 탱크 n 개의 작업 을 부여 하고 자동 으로 실행 합 니 다. 실행 과정 에서 모든 작업 이 실 행 될 때 까지 메 인 라인 이 막 힙 니 다.실행 이 끝 난 후 결 과 를 Future 대상 에 저장 하고 Future. get () 대상 을 통 해 결 과 를 되 돌려 줍 니 다.
    package com.nuaa.ldm;  
    import java.util.*;  
    import java.util.concurrent.*;  
    import static java.util.Arrays.asList;  
       
    public class TaskTest {     
       static class Sum implements Callable {  
            private final longfrom;  
            private final long to;  
                Sum(long from,long to) {  
                this.from = from;  
                this.to = to;  
            }         
            @Override  
            public Long call() {  
                long acc = 0;  
                for (long i =from; i <= to; i++) {  
                    acc = acc + i;  
                }  
                return acc;  
            }       
        }     
        public static void main(String[] args) throws Exception {         
            ExecutorService executor = Executors.newFixedThreadPool(2);  
            List> results = executor.invokeAll(asList(  
                new Sum(0, 10),new Sum(100, 1000), new Sum(10000, 1000000)  
            ));  
           executor.shutdown();         
            for(Future result : results) {  
               System.out.println(result.get());  
            }    
        }   
    }  
    

    실현 방법 3:
    포크 - joint 프레임 워 크 는 work - staking 알고리즘 을 통 해 이 루어 집 니 다. 이 알고리즘 은 스케줄 링 알고리즘 입 니 다. 모든 작업 스 레 드 는 하나의 쌍 단 대기 열 로 작업 을 유지 합 니 다.포크 는 일반적인 스 레 드 탱크 처럼 작업 대기 열 끝 에 작업 을 추가 하지 않 고 대기 열 머리 에 작업 을 추가 합 니 다.작업 스 레 드 는 머리의 최신 작업 을 선택 하여 수행 합 니 다.작업 스 레 드 가 작업 을 수행 할 수 없 을 때 다른 스 레 드 의 작업 대기 열 끝 에서 작업 을 훔 쳐 수행 하려 고 합 니 다.임 무 를 수행 하지 않 고 다른 임 무 를 훔 치 는 데 실패 하면 작업 스 레 드 가 중단 된다.
    이 방법 은 작업 스 레 드 가 처음부터 임 무 를 얻 고 스 레 드 를 훔 쳐 꼬리 에서 임 무 를 훔 치 는 것 이 장점 이다.이런 스케줄 링 알고리즘 은 귀속 알고리즘 에 비교적 적합 하 다. 귀속 알고리즘 은 분할 사상 을 채택 하여 초기 에 발생 한 임무 단원 이 비교적 크기 때문에 훔 친 비교적 큰 임 무 는 귀속 분해 하기 때문에 꼬리 부분의 훔 친 횟수 를 줄인다.또한 부모 임 무 는 하위 작업 (join) 을 기 다 려 야 할 가능성 이 높 기 때문에 대기 열 머리 부분 작업 부터 수행 하 는 것 도 최적화 입 니 다.
    한 마디 로 하면 제 한 된 스 레 드 를 사용 하여 대량의 임 무 를 수행 하 는 동시에 각 스 레 드 의 임 무 는 모두 바 쁜 집행 상태 에 있 고 스 레 드 가 대기 상태 에 있 지 않도록 한다.이 를 위해 다른 스 레 드 의 작업 대기 열 에서 작업 을 훔 쳐 수행 할 수 있 기 때문에 work - stealing 이 라 고 합 니 다.
    피 보 나치 수 계산
    package com.nuaa.ldm;  
    import java.math.BigInteger;  
    import java.util.concurrent.ExecutionException;  
    import java.util.concurrent.ForkJoinPool;  
    import java.util.concurrent.Future;  
    import java.util.concurrent.RecursiveTask;  
    public class Fibonacci extends RecursiveTask{  
         int n ;  
         public Fibonacci() {  
         }  
         Fibonacci(int i) {  
                  this.n = i;  
         }  
           private BigInteger compute(int small) {  
                 final int[] results = { 1, 1, 2, 3, 5,8, 13, 21, 34, 55, 89 };  
                 return new BigInteger(results[small]+"");  
             }  
         @Override  
         protected BigIntegercompute() {  
                  if(n < 10){ //     ,        
                            return  compute(n);  
                  }  
                  System.out.println(Thread.currentThread().getName()+"");  
                  Fibonacci f1=  new Fibonacci(n-1);//       
                  Fibonacci f2=  new Fibonacci(n-2);//        
                  f2.fork();//       
                  return f1.compute().add(f2.join());//            
         }  
         public static voidmain(String[] args) {  
                  /*       ,          ,    */  
                  ForkJoinPool forkJoinPool = new ForkJoinPool();  
                  Fibonacci fibonacci =  new Fibonacci(50);//      
                  Future result = forkJoinPool.submit(fibonacci);  
                  try {  
                            System.out.println(result.get());  
                  } catch(InterruptedException e) {  
                            e.printStackTrace();  
                  } catch(ExecutionException e) {  
                            e.printStackTrace();  
                  }                  
                   
         }     
    }  
    

    복잡 한 예:
    package com.nuaa.ldm;  
       
    import java.util.concurrent.ForkJoinPool;  
    import java.util.concurrent.RecursiveAction;  
     
     
    /**   1^2+2^2+3^2+4^2+5^2+6^2         ,              ,         
     * */  
    public class FibonacciAction extends RecursiveAction{  
         final double[] array;  
            final int lo, hi;  
            double result;  
            FibonacciAction next; // keeps track ofright-hand-side tasks  
            FibonacciAction(double[] array, int lo, inthi, FibonacciAction next) {  
              this.array = array; this.lo = lo; this.hi= hi;  
              this.next = next;  
            }  
          /*       [l,h)   */  
            double atLeaf(int l, int h) {  
              double sum = 0;  
              for (int i = l; i < h; ++i) // performleftmost base step  
                sum += array[i] * array[i];  
              return sum;  
            }  
            /*  (    )*/  
            protected void compute() {  
              int l = lo;  
              int h = hi;  
              FibonacciAction right = null;  
              /*  ,    SurplusQueuedTaskCount  3*/  
              while (h - l > 1 &&getSurplusQueuedTaskCount() <= 3) {  
                 int mid = (l + h) >>> 1;  
                 /*       */  
                 right = new FibonacciAction(array, mid,h, right);  
                 right.fork();  
                 h = mid;  
              }  
              double sum = atLeaf(l, h);  
              while (right != null) {  
                       /*                  ,    ,          */  
                 if (right.tryUnfork()) // directlycalculate if not stolen  
                   sum += right.atLeaf(right.lo,right.hi);  
                else {  
                         /*      */  
                   right.join();  
                   sum += right.result;  
                 }  
                 right = right.next;  
               }  
              result = sum;  
            }  
          
         public static voidmain(String[] args) {  
                  System.out.println(sumOfSquares(newForkJoinPool(),new double[]{1,2,3,4,5,6}));  
         }  
         static  double sumOfSquares(ForkJoinPool pool,double[] array) {  
                     int n = array.length;  
                     FibonacciAction a = newFibonacciAction(array, 0, n, null);  
                     pool.invoke(a);  
                     return a.result;  
                   }  
    }  
    

    그 중에서 getSurplusQueued TaskCount () 방법 은 현재 작업 스 레 드 가 가지 고 있 는 작업 의 예상 수량 을 통계 하고 작업 스 레 드 를 잠 그 면 도 둑 맞 을 수 있 는 fork 의 하위 작업 수량 을 공제 합 니 다.
    try Unfork () 방법 은 새 fork 작업 을 취소 하려 고 시도 합 니 다. true 로 돌아 가 는 것 을 취소 하지 않 으 면 false 로 돌아 갑 니 다.

    좋은 웹페이지 즐겨찾기