피의 교훈 - 제출 스레드 풀을 사용하고 올바른 방법을 실행하는 방법

혈액 배경 교훈 : 재고 데이터 마이그레이션의 스레드 풀을 사용하지만, 마이그레이션이 실패 할 데이터의 수, 예외 로그 인쇄는 항상있다

살인의 원인

나는 들었 parallelStream매일 개발하기 때문에 병렬 흐름이, 좋은 일이 stream많은 장면 직렬 스트림, 바로 적용 할 수있는 마이그레이션 프로그램을 작성할 필요, 즉 * 그 다음 지금 설치하지 마십시오 신속하게 설치하게하지, 경우 . 또한 재치 알고 , 일반적인 포크의 사용 / 이러한 기능을 수행하기 위해 풀에 참가, 풀은 기본적으로 모든 병렬 스트림에 의해 공유되는, 포크 / 수영장 각 프로세서에 대해 스레드를 할당합니다 조인 JVM 배경에 , 대응을 해결 방법으로 자신의 스레드 풀을 만드는 것입니다

ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
pool.submit(() -> {
            list.parallelStream().collect(Collectors.toList());
        });
复制代码

그래서 여기에서 심어 지뢰.

제출하거나 실행

  public static void main(String[] args) throws InterruptedException, ExecutionException {
        final ExecutorService pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
        List<Integer> list = Lists.newArrayList(1, 2, 3, null);
        //1.使用submit
        pool.submit(() -> {
            list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
        });
        TimeUnit.SECONDS.sleep(3);
        //2.使用 execute
        pool.execute(() -> {
            list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
        });
        //3.使用submit,调用get()
        pool.submit(() -> {
            list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
        }).get();
        TimeUnit.SECONDS.sleep(3);
    }
复制代码

위의 사용 사례에서 실행하는 독자는, 별도의 찾을 submit방법 및 오류 로그를 인쇄 사용하지 않습니다 execute오류 로그를 인쇄하는 방법을하지만, 할 submit받는 돌아 FutureJoinTask호출 get()예외가 발생합니다 방법. 따라서 진실 더티 데이터의 일부 배치에 존재하는 데이터가 널 값, 널 값은 예외가 발생 될 때 통과하는 것이 아니라 예외 로그에 submit실시간 처리를 잡을 아닌 (상처)를 인쇄한다 캐치되지 않는 예외는 반환 된 클래스 결과에 포장되어 FutureJoinTask, 다시 포기하지 않았다.

비동기 결과를 반환하지 않는 경우, 사용하지 마십시오 submit방법을

결론은 첫째, 나는 평범한 생각, 실수를 submit하고 execute의 차이는 단지 비동기 결과에 반환하고, 단계가 결과를 반환하지 않지만, 사실은 잔인. 에서 submit()논리는 비동기 작업을 던져 예외를 catch하는 것 포함해야하지만, 부적절한 사용하기 때문에 예외가 다시 발생하지 않는 원인이되었다.

이제 질문을 물어 ForkJoinPool#submit()답례로 ForkJoinTask, 비동기 작업의 결과를 얻을 수 있습니다를 지금 비동기 예외가 발생, 우리는 어떻게 될 작업의 결과를 얻으려고? 우리는 직접 볼 ForkJoinTask#get()소스.

public final V get() throws InterruptedException, ExecutionException {
    int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
        doJoin() : externalInterruptibleAwaitDone();
    Throwable ex;
    if ((s &= DONE_MASK) == CANCELLED)
        throw new CancellationException();
    //这里可以直接看到,异步任务出现异常会在调用get()获取结果的时候,会被包装成ExecutionException再次抛出
    if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
        throw new ExecutionException(ex);
    return getRawResult();
}
复制代码

GET () 결과를 얻기를 호출 할 때 비동기 작업에 이상이 될 것으로 포장됩니다 ExecutionException다시 발생하지만, 예외가 포착되는 경우는? 모든 스레드 스레드가 다시 작성해야하는, 동일하게 유지 Thread#run(), 방법을 게시 ForkJoinPool로 포장됩니다 스레드 ForkJoinWorkerThread, 그래서 우리는보고 ForkJoinWorkerThread#run()구현입니다.

public void run() {
    if (workQueue.array == null) { // only run once
        Throwable exception = null;
        try {
            onStart();
            pool.runWorker(workQueue);
        } catch (Throwable ex) {
            //出现异常,捕获,再次抛出会在调用ForkJoinTask#get()的时候
            exception = ex;
        } finally {
            try {
                onTermination(exception);
            } catch (Throwable ex) {
                if (exception == null)
                    exception = ex;
            } finally {
                pool.deregisterWorker(this, exception);
            }
        }
    }
}
复制代码

위의 분석을 기반으로 ForkJoinPool, 스레드 풀의 전부는 아닙니다 submitexecute실현과 같이, 우리는 종종 스레드 풀을 사용하는 ThreadPoolThread것입니다 무엇을 달성하기 위해, 같은 생각, 우리는 필요 에 전달 찾을 ThreadPoolThread궁극적으로 포장됩니다 비동기 작업 이는 Thread서브 클래스 나 구현 java.lang.Runnable#run, 대답은java.util.concurrent.FutureTask

 public void run() {
      ...
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    //捕获异常
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } 
     ....
    }

复制代码

개요

java.util.concurrent.ExecutorService#submit(java.lang.Runnable)이러한 스레드 풀 설정, 사실, 우리의 생각은하지만,에 스레드 풀에가 제한되어서는 안되는 이유 는 비정상적인 결과가 비동기인지, 비동기 작업 결과를 획득 , FutureTaskJDK 등의 동시성 도구를 제공 우리는 아주 좋은 대답이 부여 된 실행 비동기 작업이 발생 나타나면 또한 비동기 비정상적인 결과에 속하는 결과 비동기 작업을 얻을를, 이상은, 결과를 얻는 작업은 예외가 재 포장한다

저자 : PLZ 빨간색 스카프 나에게 전화

출처 : juejin.im/post/5d15c4 ...

그렇지 않으면 법적 책임을 추구 할 수있는 권리를이 블로그를 다시 인쇄하지만,이 섹션에 의해 선언 된 저자의 동의가 유지되어야하지 않고, 및 기사 페이지의 명백한 위치에 원래 연결을 제공에 오신 것을 환영합니다. 코드 워드가 쉽지 않다, 내 글의 요점을 찬양하는 가장 큰 힘이다

추천

출처juejin.im/post/5d15c430f265da1bab29c1fe