자바 병렬 프로 그래 밍 및 동기 화 방법
7898 단어 자바 다 중 프로 세 스 프로 그래 밍
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 로 돌아 갑 니 다.