자바 스 레 드-비동기 실행 결과 가 져 오기(FutureTask)

5848 단어 Java스 레 드
FutureTask 는 실행 결 과 를 비동기 로 가 져 오 거나 작업 을 취소 하 는 장면 에 사용 할 수 있 으 며,Runnable 또는 Callable 작업 을 통 해 FutureTask 에 전송 하고,run()방법 을 호출 하여 스 레 드 풀 에 넣 은 후 외부 FutureTask 의 get()방법 으로 결 과 를 얻 을 수 있 습 니 다.Future Task 는 주로 시간 이 많이 걸 리 는 계산 에 사용 된다.
1.다 중 태 스 크 계산 수행
Future Task 와 ExecutorService 를 이용 하여 다 중 스 레 드 방식 으로 계산 작업 을 제출 할 수 있 습 니 다.주 스 레 드 는 다른 작업 을 계속 수행 할 수 있 습 니 다.주 스 레 드 가 하위 스 레 드 의 계산 결 과 를 필요 로 할 때 비동기 적 으로 하위 스 레 드 의 실행 결 과 를 얻 을 수 있 습 니 다.코드 는 다음 과 같 습 니 다:
public class Thread_Pool_FutureTask_MutiCompute {

    public static void main(String args[]){

        Thread_Pool_FutureTask_MutiCompute thread_Pool_FutureTask_MutiCompute=new Thread_Pool_FutureTask_MutiCompute();
        //       
        List> taskList = new ArrayList>();
        //      
        ExecutorService exec = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            //   Callable    FutureTask  
            FutureTask ft = new FutureTask(thread_Pool_FutureTask_MutiCompute.new ComputeTask(i, "" + i));
            taskList.add(ft);
            //           ,     exec.invokeAll(taskList)         ;
            exec.submit(ft);
        }

        System.out.println("          ,           !");

        //              
        Integer totalResult = 0;
        for (FutureTask ft : taskList) {
            try {
                //FutureTask get       ,          
                totalResult = totalResult + ft.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

        //      
        exec.shutdown();
        System.out.println("           :" + totalResult);
    }
    private class ComputeTask implements Callable {

        private Integer result = 0;
        private String taskName = "";

        public ComputeTask(Integer iniResult, String taskName) {
            result = iniResult;
            this.taskName = taskName;
            System.out.println("         : " + taskName);
        }

        public String getTaskName() {
            return this.taskName;
        }

        @Override
        public Integer call() throws Exception {
            // TODO Auto-generated method stub

            for (int i = 0; i < 100; i++) {
                result = +i;
            }
            //   5  ,       ,              ,    FutureTask          。
            Thread.sleep(5000);
            System.out.println("       : " + taskName + "     !");
            return result;
        }
    }
}

계산 결 과 는 다음 과 같다.
         : 0
         : 1
         : 2
         : 3
         : 4
         : 5
         : 6
         : 7
         : 8
         : 9
          ,           !
       : 4     !
       : 0     !
       : 2     !
       : 1     !
       : 3     !
       : 5     !
       : 7     !
       : 6     !
       : 9     !
       : 8     !
           :990

2.높 은 병발 환경 에서
Future Task 는 높 은 병발 환경 에서 임 무 를 한 번 만 수행 하도록 확보한다.많은 높 은 병발 환경 에서 우 리 는 종종 어떤 임 무 를 한 번 만 수행 해 야 한다.이런 사용 상황 은 Future Task 의 특성 이 감당 할 수 있다.예 를 들 어 키 가 있 는 연결 탱크 가 있다 고 가정 하면 키 가 존재 할 때 키 가 대응 하 는 대상 을 직접 되 돌려 줍 니 다.키 가 존재 하지 않 을 때 연결 을 만 듭 니 다.이러한 응용 장면 에 대해 일반적으로 사용 하 는 방법 은 하나의 Map 대상 을 사용 하여 key 와 연결 탱크 에 대응 하 는 대응 관 계 를 저장 하 는 것 이다.전형 적 인 코드 는 다음 과 같다.

private Map connectionPool = new HashMap();
private ReentrantLock lock = new ReentrantLock();

public Connection getConnection(String key) {
    try {
        lock.lock();
        if (connectionPool.containsKey(key)) {
            return connectionPool.get(key);
        } else {
            //   Connection  
            Connection conn = createConnection();
            connectionPool.put(key, conn);
            return conn;
        }
    } finally {
        lock.unlock();
    }
}

//  Connection  
private Connection createConnection() {
    return null;
}

위의 예 에서 우 리 는 자 물 쇠 를 추가 하여 높 은 병발 환경 에서 의 스 레 드 안전 을 확보 하고 connection 을 한 번 만 만 들 도록 확 보 했 으 나 성능 을 희생 했다.Concurrent Hash 로 바 꾼 경우 잠 금 동작 을 거의 피 할 수 있 고 성능 이 크게 향상 되 었 으 나 높 은 병발 상황 에서 Connection 이 여러 번 생 성 되 는 현상 이 나타 날 수 있 습 니 다.이때 가장 해결 해 야 할 문 제 는 key 가 존재 하지 않 을 때 Connection 을 만 드 는 동작 을 connection Pool 이후 에 실행 할 수 있다 는 것 이다.이것 이 바로 Future Task 가 역할 을 발휘 할 시기 이다.Concurrent HashMap 과 Future Task 를 바탕 으로 하 는 개조 코드 는 다음 과 같다.
 private ConcurrentHashMap> connectionPool = new ConcurrentHashMap>();
 
    public Connection getConnection(String key) throws Exception {
        FutureTask connectionTask = connectionPool.get(key);
        if (connectionTask != null) {
            return connectionTask.get();
        } else {
            Callable callable = new Callable() {
                @Override
                public Connection call() throws Exception {
                    // TODO Auto-generated method stub  
                    return createConnection();
                }
            };
            FutureTask newTask = new FutureTask(callable);
            connectionTask = connectionPool.putIfAbsent(key, newTask);
            if (connectionTask == null) {
                connectionTask = newTask;
                connectionTask.run();
            }
            return connectionTask.get();
        }
    }
 
    //  Connection  
    private Connection createConnection() {
        return null;
    }

좋은 웹페이지 즐겨찾기