2017-01-22 1 views
-2

나는 자바로 멀티 쓰레드를 가르치고있다. 내 더미 예제는 내가 정렬하려는 레코드의 큰 목록 (2D 배열)입니다. 단일 스레드 방식은 루프를 사용하여 레코드 목록을 정렬하고 정렬하는 것입니다. 다중 스레드를 사용하여 프로그램을 고정 소수점 스레드 (이 경우에는 2)로 정렬하려고합니다. 한 스레드는 목록의 첫 번째 절반을 정렬하고 두 번째 스레드는 나머지 절반을 정렬합니다. 이제 정렬 된 레코드 목록의 결과를 출력하고 싶습니다.Java에서 다중 스레드를 사용하여 레코드 목록을 정렬하려면 어떻게합니까?

어떻게 작업자 스레드 풀을 만들고 레코드 목록을 정렬 할 수 있습니까? data이 공유 리소스가 될까 걱정합니까? 어떻게 각 스레드의 결과를 원래 레코드 목록으로 되돌려 놓을 수 있습니까? 아래는 제 코드입니다.

import java.util.*; 

class RunnableProcess implements Runnable { 
    private int[] data; 

    public RunnableProcess(int[] data) { 
     this.data = data; 
    } 

    public void run() { 
    try { 

     // sort the records this thread has access to 
     for (int i = 0; i < data.length; i++) { 
     Arrays.sort(data[i]); 
     } 

    } catch(Exception ex) { 
     ex.printStackTrace(); 
    } 
    } 
} 

class BigData { 

    static int[][] data = new int[1000][1000]; 

    public static void main(String [] args) { 


    // Create records 
    for (int i = 0; i < data.length; i++) { 
     for (int j = 0; j < data[0].length; j++) { 
     data[i][j] = new Random().nextInt(999); 
     } 
    } 

    // Call on two threads to sort the data variable 
    // ExecutorService executor = Executors.newFixedThreadPool(2); 


    // Python type of idea: Pass half the records to each thread and start 
    // java doesn't support this so what is the java way of doing this? 

    // Thread thread = new Thread(new RunnableProcess(data[:499])); 
    // thread.start(); 

    // Thread thread = new Thread(new RunnableProcess(data[499:])); 
    // thread.start(); 

    } 
} 

나는이 문제를 해결하는 가장 좋은 방법에 열려 제안입니다.

+2

'ArrayList' 및 ['ArrayList <> #subList()']를보십시오 (https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#subList (int , % 20int)) – AJNeufeld

+0

세 번째 단계는 잊었습니다. 정렬 된 결과를 병합하십시오. 병합 정렬 알고리즘을 살펴보십시오! –

답변

1

Java는 파이썬과 같은 방식으로 원시 배열을 조각 내기를 지원하지 않습니다. ArrayList을 사용하여 가까와 질 수 있습니다.

먼저, 제쳐두고. 무작위 데이터 생성은 매우 비효율적입니다. 생성하는 각 난수에 대해 새 Random 숫자 생성기 개체를 만듭니다. 당신은 다음과 같이 하나 개의 발전기가 필요하면 데이터를 생성하면

Random rnd = new Random();      // Only created once 
for (int i = 0; i < data.length; i++) { 
    for (int j = 0; j < data[0].length; j++) { 
     data[i][j] = rnd.nextInt(999); 
    } 
} 

, 우리는 각 레코드는 int[] 1D 배열은 레코드 List으로이 기본 int[][] 2 차원 배열을 설정할 수 있습니다 :

List<int[]> records = Arrays.asList(data); 

이 값은 배열의 값을 복사하지 않습니다. 어레이의 List보기를 작성합니다. data에 저장된 값을 변경하면 records에 반영되고 그 반대의 경우도 마찬가지입니다.

이렇게하면 List#subList() 방법을 사용하여 목록을 두 개의보기로 나눌 수 있습니다.

List<int[]> first_half = records.subList(0, 500); 
List<int[]> second_half = records.subList(500, 1000); 

다시 말하지만, 원래 목록에 의해 뒷받침 된 원본 목록에 기반한보기입니다. 보기를 통해 변경 한 내용은 원본에 반영됩니다. 우리는 이제 배열 대신하는 List에 저장된 기록을 가지고 있기 때문에

, 우리는 RunnableProcess이 새로운 형식을 사용하도록 업데이트해야합니다

class RunnableProcess implements Runnable { 
    private List<int[]> records; 

    public RunnableProcess(List<int[]> records) { 
     this.records = records; 
    } 

    @Override 
    public void run() { 
     // sort the records this thread has access to 
     for (int[] record : records) { 
      Arrays.sort(record); 
     } 
    } 
} 
우리는 이제 데이터가 두 개의 독립적 인 세트로 분할 한

, 각 세트에서 작동 할 수있는 RunnableProcess이 있습니다. 이제 멀티 스레딩을 시작할 수 있습니다.

이 실행 프로그램 서비스는 두 개의 스레드 풀을 작성하고이 스레드를이 실행 프로그램에 제출 된 후속 태스크에 대해 반복적으로 재사용합니다. 이로 인해 이 아닌이 자신의 스레드를 만들고 시작해야합니다. 유언 집행 인이이를 처리 할 것입니다.

executor.submit(new RunnableProcess(first_half)); 
executor.submit(new RunnableProcess(second_half)); 
우리는 이러한 작업이 모두 완료되면, 우리는 Futureexecutor.submit()에서 반환 저장해야합니다 알고 싶어하기 때문에

:

Future<?> task1 = executor.submit(new RunnableProcess(first_half)); 
Future<?> task2 = executor.submit(new RunnableProcess(second_half)); 

완료 할 작업에 대한 Future#get() 대기를 호출하고 결과를 검색 작업.

task1.get(); // Wait for first task to finish ... 
task2.get(); // ... as well as the second task to finish. 

마지막으로 실행 프로그램을 #shutdown()해야하거나 프로그램이 제대로 종료하지 않을 수 있습니다 (우리 Runnable가 값을 반환하지 않습니다 때문에 null 값이 반환됩니다. 참고).

executor.shutdown(); 

전체 예제 :

List<int[]> records = Arrays.asList(data); 
List<int[]> first_half = records.subList(0, 500); 
List<int[]> second_half = records.subList(500, 1000); 

ExecutorService executor = Executors.newFixedThreadPool(2); 

try { 
    Future<?> task1 = executor.submit(new RunnableProcess(first_half)); 
    Future<?> task2 = executor.submit(new RunnableProcess(second_half)); 

    task1.get(); // Wait for first task to finish ... 
    task2.get(); // ... as well as the second task to finish. 
} catch (InterruptedException | ExecutionException e) { 
    e.printStackTrace(); 
} 

executor.shutdown(); 

내가 데이터가 공유 자원 것에 대해 걱정해야합니까?

이 경우, 아니오. data은 배열의 배열입니다. 각 스레드는 int[] 레코드에 대한 참조를 얻기 위해 data 배열 (List) 만 참조하고 있습니다. data 배열 자체는 수정되지 않습니다. 레코드 만 있지만 각 스레드는 스레드 중 하나에 의해 수정됩니다.

어떻게 각 스레드의 결과를 원래 레코드 목록으로 되돌려 놓을 수 있습니까?

레코드가 "제자리에"정렬되기 때문에 data 변수에 이미 정렬 된 레코드 배열이 포함되어 있습니다. Future#get()을 호출하면 각 Thread이 처리를 완료 했으므로 데이터가 주 스레드에서 안전하게 다시 액세스 될 수 있습니다.

관련 문제