자바 병렬 프로 그래 밍:스 레 드 를 어떻게 만 듭 니까?

이 시 리 즈 는 전재 로 원문 에서 나 왔 다.http://www.cnblogs.com/dolphin0520/p/3913517.html
앞의 글 에 서 는 프로 세 스 와 스 레 드 의 유래 를 다 루 었 습 니 다.오늘 은 자바 에서 스 레 드 를 어떻게 만 드 는 지,스 레 드 로 하여 금 키 임 무 를 수행 하 게 하 는 방법 을 말씀 드 리 겠 습 니 다.자바 의 응용 프로그램 과 프로 세 스 에 관 한 개념 지식 을 먼저 설명 한 다음 에 스 레 드 를 만 드 는 방법 과 프로 세 스 를 만 드 는 방법 을 논술 한다.다음은 본문의 목록 대강 이다.
응용 프로그램 과 프로 세 스 관련 개념
2.자바 에서 스 레 드 를 만 드 는 방법
3.자바 에서 프로 세 스 를 만 드 는 방법
잘못된 점 이 있 으 면 양해 해 주시 고 비판 지적 을 환영 해 주 십시오.
작가 의 노동 성 과 를 존중 하고 전재 하 시 려 면 원문 링크 를 표시 하 십시오.
  http://www.cnblogs.com/dolphin0520/p/3913517.html
응용 프로그램 과 프로 세 스 관련 개념
자바 에서 하나의 응용 프로그램 은 JVM 인 스 턴 스(JVM 프로 세 스 라 고도 부 르 는 곳 도 있 습 니 다)에 대응 합 니 다.일반적으로 이름 은 자바.exe 또는 자바 w.exe(windows 에서 작업 관리 자 를 통 해 볼 수 있 습 니 다)입 니 다.자바 는 단일 스 레 드 프로 그래 밍 모델 을 사용 합 니 다.즉,우리 자신의 프로그램 에서 스 레 드 를 주동 적 으로 만 들 지 않 으 면 하나의 스 레 드 만 만 만 듭 니 다.보통 주 스 레 드 라 고 합 니 다.그러나 주의해 야 할 것 은 하나의 스 레 드 만 작업 을 수행 하 는 것 이지 JVM 에 하나의 스 레 드 만 있 는 것 은 아 닙 니 다.JVM 인 스 턴 스 는 생 성 할 때 다른 스 레 드(예 를 들 어 쓰레기 수집 기 스 레 드)를 많이 만 듭 니 다.
자바 는 단일 스 레 드 프로 그래 밍 모델 을 사용 하기 때문에 UI 프로 그래 밍 을 할 때 시간 이 걸 리 는 작업 을 하위 스 레 드 에 두 어 진행 해 야 합 니 다.메 인 스 레 드 를 막 지 않도록 해 야 합 니 다.
2.자바 에서 스 레 드 를 만 드 는 방법
자바 에서 스 레 드 를 만 들 려 면 보통 두 가지 방법 이 있 습 니 다.1)Thread 류 를 계승 합 니 다.2)Runnable 인 터 페 이 스 를 실현 한다.
1.Thread 클래스 계승
Thread 클래스 를 계승 하려 면 run 방법 을 다시 써 야 합 니 다.run 방법 에서 실행 할 작업 을 정의 해 야 합 니 다.
class MyThread extends Thread{
    private static int num = 0;

    public MyThread(){
        num++;
    }

    @Override
    public void run() {
        System.out.println("      "+num+"   ");
    }
}

자신의 스 레 드 클래스 를 만 든 후에 스 레 드 대상 을 만 들 고 start()방법 으로 스 레 드 를 시작 할 수 있 습 니 다.run()방법 으로 스 레 드 를 시작 하 는 것 이 아 닙 니 다.run 방법 에 서 는 실행 해 야 할 작업 만 정의 합 니 다.run 방법 을 호출 하면 주 스 레 드 에서 run 방법 을 실행 하 는 것 과 같 습 니 다.일반적인 방법 으로 호출 하 는 것 과 다 르 지 않 습 니 다.이 때 는 새로운 스 레 드 를 만들어 정 의 를 수행 하지 않 습 니 다.
public class Test {
    public static void main(String[] args)  {
        MyThread thread = new MyThread();
        thread.start();
    }
}


class MyThread extends Thread{
    private static int num = 0;

    public MyThread(){
        num++;
    }

    @Override
    public void run() {
        System.out.println("      "+num+"   ");
    }
}

start()방법 을 호출 하면 새로운 스 레 드 를 만 들 수 있 습 니 다.start()방법 호출 과 run()방법 호출 의 차 이 를 구분 하기 위해 다음 예 를 보십시오.
public class Test {
    public static void main(String[] args)  {
        System.out.println("   ID:"+Thread.currentThread().getId());
        MyThread thread1 = new MyThread("thread1");
        thread1.start();
        MyThread thread2 = new MyThread("thread2");
        thread2.run();
    }
}


class MyThread extends Thread{
    private String name;

    public MyThread(String name){
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("name:"+name+"    ID:"+Thread.currentThread().getId());
    }
}


실행 결과:
출력 결과 에서 다음 과 같은 결론 을 얻 을 수 있다.
1)thread 1 은 thread 2 의 스 레 드 ID 와 달리 thread 2 는 메 인 스 레 드 ID 와 같 습 니 다.run 방법 으로 호출 하면 새로운 스 레 드 를 만 들 지 않 고 메 인 스 레 드 에서 run 방법 을 직접 실행 하 며 일반적인 방법 으로 호출 하 는 것 과 다 르 지 않 습 니 다.
2)thread 1 의 start 방법 은 thread 2 의 run 방법 앞에서 호출 되 지만 먼저 thread 2 의 run 방법 호출 에 관 한 정 보 를 출력 합 니 다.새 스 레 드 생 성 과정 이 주 스 레 드 의 후속 실행 을 막 지 않 음 을 설명 합 니 다.
2.Runnable 인터페이스 구현
자바 에서 스 레 드 를 만 드 는 것 은 Thread 클래스 를 계승 하 는 것 외 에 도 Runnable 인 터 페 이 스 를 실현 하여 유사 한 기능 을 실현 할 수 있 습 니 다.Runnable 인 터 페 이 스 를 실현 하려 면 run 방법 을 다시 써 야 합 니 다.
다음은 하나.
public class Test {
    public static void main(String[] args)  {
        System.out.println("   ID:"+Thread.currentThread().getId());
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}


class MyRunnable implements Runnable{

    public MyRunnable() {

    }

    @Override
    public void run() {
        System.out.println("   ID:"+Thread.currentThread().getId());
    }
}

Runnable 의 중국어 뜻 은'임무'입 니 다.말 그대로 Runnable 인 터 페 이 스 를 실현 함으로써 우 리 는 하위 임 무 를 정의 한 다음 에 하위 임 무 를 Thread 에 맡 깁 니 다.이 방식 은 Runnable 을 Thread 류 의 매개 변수 로 한 다음 Thread 의 start 방법 으로 새 스 레 드 를 만들어 서 이 하위 작업 을 수행 해 야 합 니 다.Runnable 의 run 방법 을 호출 하면 새 스 레 드 를 만 들 지 않 습 니 다.이 일반적인 방법 은 다 르 지 않 습 니 다.
사실 Thread 류 의 실현 소스 코드 를 보면 Thread 류 가 Runnable 인 터 페 이 스 를 실현 한 것 을 발견 할 수 있 습 니 다.
자바 에서 이 두 가지 방식 은 모두 스 레 드 를 만들어 하위 작업 을 수행 할 수 있 습 니 다.구체 적 으로 어떤 방식 을 선택 하 느 냐 에 따라 자신의 요 구 를 볼 수 있 습 니 다.Thread 클래스 를 직접 계승 하면 Runnable 인 터 페 이 스 를 실현 하 는 것 보다 더 간결 해 보일 수 있 지만 자바 가 단일 계승 만 허용 하기 때문에 사용자 정의 클래스 가 다른 클래스 를 계승 해 야 한다 면 Runnable 인 터 페 이 스 를 실현 하 는 것 만 선택 할 수 있 습 니 다.
3.자바 에서 프로 세 스 를 만 드 는 방법
자바 에 서 는 두 가지 방식 으로 프로 세 스 를 만 들 수 있 으 며,모두 5 개의 주요 클래스 와 관련된다.
첫 번 째 방법 은 Runtime.exec()방법 으로 프로 세 스 를 만 드 는 것 이 고,두 번 째 방법 은 ProcessBuilder 의 start 방법 으로 프로 세 스 를 만 드 는 것 입 니 다.다음은 이 두 가지 방식 의 차이 와 관 계 를 살 펴 보 자.
먼저 말 해 야 할 것 은 Process 류 이 고 Process 류 는 추상 류 이다.그 안에 몇 가지 추상 적 인 방법 이 있다.이것 은 Process 류 의 소스 코드 를 보면 알 수 있다.
java.lang.Process 경로 아래 에 있 습 니 다:
public abstract class Process
{   
    abstract public OutputStream getOutputStream();   //        

    abstract public InputStream getInputStream();    //        

    abstract public InputStream getErrorStream();   //        

    abstract public int waitFor() throws InterruptedException;   //     

    abstract public int exitValue();   //         

    abstract public void destroy();   //    
}

1)ProcessBuilder 를 통 해 프로 세 스 를 만 듭 니 다.ProcessBuilder 는 final 클래스 입 니 다.두 개의 구조 기 가 있 습 니 다.
public final class ProcessBuilder
{
    private List command;
    private File directory;
    private Map environment;
    private boolean redirectErrorStream;

    public ProcessBuilder(List command) {
    if (command == null)
        throw new NullPointerException();
    this.command = command;
    }

    public ProcessBuilder(String... command) {
    this.command = new ArrayList(command.length);
    for (String arg : command)
        this.command.add(arg);
    }
}

구조 기 는 만들어 야 할 프로 세 스 의 명령 매개 변 수 를 전달 합 니 다.첫 번 째 구조 기 는 명령 매개 변 수 를 List 에 넣 고 전달 하 는 것 입 니 다.두 번 째 구조 기 는 정 해 지지 않 은 긴 문자열 로 전 달 됩 니 다.
그러면 우 리 는 이어서 아래 를 살 펴 보 겠 습 니 다.앞에서 언급 한 것 은 ProcessBuilder 의 start 방법 을 통 해 새로운 프로 세 스 를 만 드 는 것 입 니 다.start 방법 에서 구체 적 으로 어떤 일 을 했 는 지 살 펴 보 겠 습 니 다.다음은 start 방법의 구체 적 인 실현 소스 코드 입 니 다.
public Process start() throws IOException {
// Must convert to array first -- a malicious user-supplied
// list might try to circumvent the security check.
String[] cmdarray = command.toArray(new String[command.size()]);
for (String arg : cmdarray)
    if (arg == null)
    throw new NullPointerException();
// Throws IndexOutOfBoundsException if command is empty
String prog = cmdarray[0];

SecurityManager security = System.getSecurityManager();
if (security != null)
    security.checkExec(prog);

String dir = directory == null ? null : directory.toString();

try {
    return ProcessImpl.start(cmdarray,
                 environment,
                 dir,
                 redirectErrorStream);
} catch (IOException e) {
    // It's much easier for us to create a high-quality error
    // message than the low-level C code which found the problem.
    throw new IOException(
    "Cannot run program \"" + prog + "\""
    + (dir == null ? "" : " (in directory \"" + dir + "\")")
    + ": " + e.getMessage(),
    e);
}
}

이 방법 은 Process 대상 을 되 돌려 줍 니 다.이 방법의 앞부분 은 명령 매개 변수 와 설 정 된 작업 디 렉 터 리 에 따라 매개 변 수 를 설정 하 는 것 과 같 습 니 다.가장 중요 한 것 은 try 구문 블록 에 있 는 한 마디 입 니 다.
return ProcessImpl.start(cmdarray,
                    environment,
                    dir,
                    redirectErrorStream);

프로 세 스 를 진정 으로 만 드 는 것 은 이 문장 입 니 다.프로 세 스 Impl 류 의 start 방법 을 호출 하 는 것 을 주의 하 십시오.start 는 반드시 정적 인 방법 임 을 알 수 있 습 니 다.그렇다면 프로 세 스 임 플 은 어떤 부류 일 까?이 클래스 역시 java.lang.ProcessImpl 경로 에 있 습 니 다.이 클래스 의 구체 적 인 실현 을 보십시오.
ProcessImpl 도 final 클래스 로 Process 클래스 를 계승 합 니 다.

final class ProcessImpl extends Process {

    // System-dependent portion of ProcessBuilder.start()
    static Process start(String cmdarray[],
             java.util.Map environment,
             String dir,
             boolean redirectErrorStream)
    throws IOException
    {
    String envblock = ProcessEnvironment.toEnvironmentBlock(environment);
    return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream);
    }
 ....
}

이것 은 ProcessImpl 류 의 start 방법의 구체 적 인 실현 이 며,사실상 start 방법 에 서 는 이 문장 을 통 해 ProcessImpl 대상 을 만 듭 니 다.
1 return new ProcessImpl(cmdarray, envblock, dir, redirectErrorStream); 한편,ProcessImpl 에서 Process 류 중의 몇 가지 추상 적 인 방법 에 대해 구체 적 으로 실현 했다.
사실상 ProcessBuilder 의 start 방법 을 통 해 ProcessImpl 대상 을 만 들 었 다 는 뜻 이다.
프로 세 스 빌 더 를 사용 하여 프로 세 스 를 만 드 는 예 를 들 어 프로 세 스 빌 더 를 통 해 cmd 를 열 고 ip 주소 정 보 를 얻 으 려 면 이렇게 쓸 수 있 습 니 다.
public class Test {
    public static void main(String[] args) throws IOException  {
        ProcessBuilder pb = new ProcessBuilder("cmd","/c","ipconfig/all");
        Process process = pb.start();
        Scanner scanner = new Scanner(process.getInputStream());

        while(scanner.hasNextLine()){
            System.out.println(scanner.nextLine());
        }
        scanner.close();
    }
}

첫 번 째 단 계 는 가장 중요 한 것 입 니 다.명령 문자열 을 ProcessBuilder 의 구조 기 에 전달 하 는 것 입 니 다.일반적으로 문자열 에 있 는 모든 독립 된 명령 을 하나의 매개 변수 로 하지만 순서대로 List 에 넣 어 전달 할 수도 있 습 니 다.
다른 많은 구체 적 인 용법 은 여기 서 군말 하지 않 습 니 다.예 를 들 어 ProcessBuilder 의 environment 방법 과 directory(File directory)를 통 해 프로 세 스 의 환경 변수 와 작업 디 렉 터 리 를 설정 하 는 등 관심 이 있 는 친 구 는 관련 API 문 서 를 볼 수 있 습 니 다.
2)Runtime 의 exec 방법 으로 프로 세 스 만 들 기
우선 Runtime 류 와 exec 방법의 구체 적 인 실현 을 살 펴 보 자.Runtime 은 말 그대로 실행 할 때 현재 프로 세 스 가 있 는 가상 컴퓨터 인 스 턴 스 를 나타 낸다.
모든 프로 세 스 가 하나의 가상 컴퓨터 인 스 턴 스 에서 만 실행 되 기 때문에 Runtime 에서 하나의 가상 컴퓨터 인 스 턴 스 만 생 성 합 니 다.
public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class Runtime are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the Runtime object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
    return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}
    ...
 }

이 를 통 해 알 수 있 듯 이 Runtime 류 의 구조 기 는 private 이기 때문에 getRuntime 을 통 해 Runtime 의 인 스 턴 스 를 얻 을 수 있 습 니 다.다음은 exec 방법 실현 에 중심 을 두 고 Runtime 에서 여러 개의 exec 의 서로 다른 재 업로드 실현 이 있 지만 마지막 으로 실 행 된 것 은 이 버 전의 exec 방법 입 니 다.
public Process exec(String[] cmdarray, String[] envp, File dir)
   throws IOException {
   return new ProcessBuilder(cmdarray)
       .environment(envp)
       .directory(dir)
       .start();
   }

실제로 Runtime 류 의 exec 를 통 해 프로 세 스 를 만 들 면 결국 ProcessBuilder 류 의 start 방법 으로 만 들 어 졌 음 을 알 수 있 습 니 다.
다음 예 를 들 어 Runtime 의 exec 를 통 해 프로 세 스 를 어떻게 만 드 는 지,아니면 앞의 예 를 들 어 cmd 를 호출 하여 ip 주소 정 보 를 얻 는 지 보 겠 습 니 다.
public class Test {
    public static void main(String[] args) throws IOException  {
        String cmd = "cmd "+"/c "+"ipconfig/all";
        Process process = Runtime.getRuntime().exec(cmd);
        Scanner scanner = new Scanner(process.getInputStream());

        while(scanner.hasNextLine()){
            System.out.println(scanner.nextLine());
        }
        scanner.close();
    }
}

주의해 야 할 것 은 exec 방법 은 부정 확 한 파 라 메 터 를 지원 하지 않 기 때문에 명령 파 라 메 터 를 연결 한 다음 에 전송 해 야 합 니 다.
자바 에서 스 레 드 와 프로 세 스 를 어떻게 만 드 는 지 에 대해 서 는 잠시 이렇게 많은 이 야 기 를 나 누 었 습 니 다.관심 이 있 는 친 구 는 관련 자 료 를 참고 할 수 있 습 니 다.
참고 자료:
 http://luckykapok918.blog.163.com/blog/static/205865043201210272168556/
 http://www.cnblogs.com/ChrisWang/archive/2009/12/02/use-java-lang-process-and-processbuilder-to-create-native-application-process.html
 http://lavasoft.blog.51cto.com/62575/15662/

《자바 프로 그래 밍 사상》.
저자:해자 출처:http://www.cnblogs.com/dolphin0520/ 본 블 로그 에 게재 되 지 않 은 글 은 저자 해자 와 블 로그 원 이 공유 하고 있 으 며,전 재 를 환영 합 니 다.그러나 작가 의 동의 없 이 는 이 성명 을 보류 하고 글 페이지 의 뚜렷 한 위치 에서 원문 연결 을 해 야 합 니 다.그렇지 않 으 면 법 적 책임 을 추궁 할 권 리 를 보류 합 니 다.

좋은 웹페이지 즐겨찾기