Java Multithreading (1)
Java의 매우 중요한 지식 지점으로서, 여전히 여기에 요약해야합니다.
1. 실의 수명주기와 5 개의 기본 상태
Java의 실의 수명주기와 관련하여 먼저 다음 고전적인 그림을 살펴 보겠습니다.
위의 그림은 기본적으로 자바에서 멀티 스레딩의 중요한 지식 지점을 다룹니다. 위 그림에서 지식 지점을 마스터하면 기본적으로 자바에서 멀티 스레딩을 마스터하게됩니다. 주로 포함 :
Java 스레드에는 5 개의 기본 상태가 있습니다
새 상태 (New) : 스레드 객체 쌍이 만들어지면 다음과 같은 새 상태가 들어갑니다. 스레드 t = new Mythread ();
준비 상태 (runnable) : 스레드 개체 (t.start ();)의 start () 메소드가 있으면 스레드가 준비 상태로 들어갑니다. 준비 상태의 스레드는 스레드가 준비되었고 CPU가 언제든지 실행을 일정하기를 기다리고 있음을 의미합니다.
실행 상태 : CPU가 준비 상태에서 스레드를 예약하기 시작하면 스레드를 진정으로 실행할 수 있습니다. 즉, 실행 상태로 들어갑니다. 참고 : 준비 상태는 실행중인 상태에 대한 유일한 항목입니다. 즉, 스레드가 실행 상태에 입력하려면 먼저 준비 상태에 있어야합니다.
차단 상태 : 어떤 이유로 든 실행 상태의 스레드는 일시적으로 CPU 사용을 포기하고 실행을 중지합니다. 현재 블로킹 상태로 들어갑니다. CPU가 다시 실행중인 상태에 들어가기 위해 다시 전화 할 기회가 없습니다. 차단 이유에 따라 차단 상태를 세 가지 유형으로 나눌 수 있습니다.
1. 차단 대기 : 실행중인 상태의 스레드는 대기 상태를 차단 상태로 입력하기 위해 대기 () 메소드를 실행합니다.
2. 동기화 된 차단- 스레드가 동기화 된 동기화 잠금을 얻지 못합니다 (잠금이 다른 스레드에 의해 점유되기 때문에) 동기화 된 차단 상태로 들어갑니다.
3. 기타 차단-스레드의 sleep () 또는 join ()을 호출하거나 I/O 요청을 발행하여 스레드가 차단 상태로 들어갑니다. Sleep () State가 시간이 초과되면 join ()는 스레드가 끝나거나 시간이 끝나기를 기다렸거나 I/O 처리가 완료되면 스레드가 준비 상태에 다시 들어갔습니다.
DEAD : 스레드는 예외로 인해 실행 () 메소드를 실행하거나 종료했으며 스레드는 수명주기를 종료합니다.
2. Java Multithreads의 생성 및 시작
Java에는 스레드 생성의 세 가지 기본 형태가 있습니다.
1. 스레드 클래스를 상속하고 클래스의 run () 메소드를 무시합니다.
클래스 Mythread는 스레드 {private int i = 0; @override public void run () {for (i = 0; i <100; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); }}} 공개 클래스 스레드 테스트 {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {Thread Mythread1 = new Mythread (); // 새 스레드 생성 Mythread1이 스레드는 새 상태에 들어갑니다. // 새 스레드 생성 mythread2이 스레드는 새 상태로 들어갑니다. Mythread1.start (); // START () 메서드를 호출하여 스레드가 준비 상태를 입력하게합니다. state mythread2.start (); // START () 메서드를 호출하여 스레드가 준비 상태를 입력하게합니다}}}}위에서 볼 수 있듯이 스레드 클래스를 상속하면, 새로운 스레드 클래스 신화는 run () 메소드의 메소드 본문이 스레드가 완료 해야하는 작업을 나타내며 스레드 실행 본체라고합니다. 이 스레드 클래스 객체를 만들 때 새 스레드가 생성되어 새 스레드 상태로 들어갑니다. 스레드 객체에서 참조 된 start () 메소드를 호출하면 스레드가 준비 상태로 들어갑니다. 현재 CPU 스케줄링 타이밍에 따라 스레드가 즉시 실행되지 않을 수 있습니다.
2. runnable 인터페이스를 구현하고 인터페이스의 run () 메소드를 재정의합니다. run () 메소드는 또한 스레드 실행 본체이며, runnable 구현 클래스의 인스턴스를 작성 하고이 인스턴스를 스레드 클래스의 대상으로 사용하여 스레드 개체를 만듭니다. 스레드 객체는 실제 스레드 객체입니다.
클래스가 감독 가능한 구현 런닝 가능한 {private int i = 0; @override public void run () {for (i = 0; i <100; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); }}} 공개 클래스 스레드 테스트 {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {runnable myrunnable = new myrunnable (); // 실행 가능한 구현 객체를 만듭니다. 클래스 스레드 스레드 1 = 새 스레드 (myrunnable); // 스레드 대상으로 myrunnable을 사용하여 새 스레드를 만듭니다. 스레드 스레드 2 = 새 스레드 (myrunnable); thread1.start (); // strest () 메서드를 호출하여 스레드가 준비 상태를 입력하게합니다. stread2.start (); }}}} 나는 모든 사람이 새로운 스레드를 만드는 위의 두 가지 방법에 익숙하다고 생각합니다. 그렇다면 스레드와 달리기 가능한 관계는 무엇입니까? 먼저 다음 예를 살펴 보겠습니다.
공개 클래스 스레드 테스트 {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {runnable myrunnable = new myrunnable (); 스레드 스레드 = 새로운 신화 (myrunnable); thread.start (); }}}} 클래스 myrunnable empless runnable {private int i = 0; @override public void run () {System.out.println ( "Myrunnable Run"); for (i = 0; i <100; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); }}} class mythread는 스레드 {private int i = 0; Public Mythread (Runnable Runnable) {Super (Runnable); } @override public void run () {System.out.println ( "Mythread Run"); for (i = 0; i <100; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); }}}마찬가지로, 런닝 가능한 인터페이스를 구현하는 스레드를 만드는 것도 마찬가지입니다. 차이점은
1 스레드 스레드 = 새 신화 (myrunnable);
그렇다면이 메소드가 새 스레드를 성공적으로 만들 수 있습니까? 대답은 예입니다. 현재 스레드 실행 본체의 경우, Myrunnable Interface 또는 Run () 메소드의 run () 메소드가 Mythread 클래스에서? 출력을 통해 스레드 실행 본체가 신화 클래스의 run () 메소드라는 것을 알고 있습니다. 실제로 스레드 클래스 자체가 런 가능한 인터페이스를 구현하고 run () 메소드가 먼저 실행 가능한 인터페이스에서 정의되기 때문에 그 이유는 매우 간단합니다.
공개 인터페이스 runnable {public Abstract void run (); } 스레드 클래스의 Runnable 인터페이스에서 run () 메소드의 구현을 살펴 보겠습니다.
@override public void run () {if (target! = null) {target.run (); }}즉, 스레드 클래스에서 run () 메소드를 실행할 때 먼저 대상이 존재하는지 여부를 결정합니다. 존재하는 경우 대상의 run () 메소드가 실행됩니다. 그러나 위에서 주어진 열에서 다형성의 존재로 인해 스레드 클래스의 run () 메소드는 전혀 실행되지 않지만 런타임 유형, 즉 Mythread 클래스의 run () 메소드가 직접 실행됩니다.
3. 호출 가능 및 향후 인터페이스를 사용하여 스레드를 만듭니다. 구체적으로, 호출 가능한 인터페이스에 대한 구현 클래스를 생성하고 Clall () 메소드를 구현합니다. FutureTask 클래스를 사용하여 Callable 구현 클래스 객체를 감싸고이 FutureTask 객체를 스레드 개체의 대상으로 사용하여 스레드를 생성하십시오.
조금 복잡해 보이지만 예제를 직접 보면 분명합니다.
공개 클래스 스레드 테스트 {public static void main (String [] args) {callable <integer> mycallable = new MyCallable (); // myCallable 객체 생성 futuretask <integer> ft = new FutureTask <integer> (myCallable); // FutureTask를 사용하여 myCallable 객체를 랩핑하여 (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {스레드 스레드 = 새 스레드 (ft); // FutureTask 객체는 스레드 개체 스레드의 대상으로 새 스레드를 생성합니다 .Start (); // 스레드가 준비 상태로 들어갑니다}}} system.out.println ( "루프의 기본 스레드가 실행되었습니다 .."); try {int sum = ft.get (); // 새로 생성 된 새 스레드 System.out.println ( "sum =" + sum)에서 call () 메소드에 의해 반환 된 결과를 가져옵니다. } catch (InterruptedException e) {e.printstacktrace (); } catch (executionException e) {e.printstacktrace (); }}} 클래스 myCallable 구현 호출 가능 <integer> {private int i = 0; // run () 메소드와 달리 Call () 메소드에는 return value @override public integer call () {int sum = 0; for (; i <100; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); 합계 += i; } 반환 합계; }}우선, Callable 인터페이스를 구현할 때 run () 메소드가 더 이상 run () 메소드가 아니라 call () 메소드임을 발견했습니다. 이 호출 () 메소드는 스레드 실행 본체이며 반환 값도 있습니다! 새 스레드를 만들 때 MyCallable 객체는 FutureTask를 통해 감싸고 스레드 객체의 대상 역할을합니다. 그런 다음 FutureTask 클래스의 정의를보십시오.
공개 클래스 FutureTask <v> runnablefuture <v> {// ....}을 구현합니다. 공개 인터페이스 runnableFuture <v>는 runnable, future <v> {void run (); }따라서 FutureTask 클래스는 실제로 실행 가능하고 미래의 인터페이스를 모두 구현하여 미래의 이중 특성과 달리기가 가능하다는 것을 발견했습니다. 실행 가능한 기능을 통해 스레드 객체의 대상으로 사용할 수 있으며 향후 기능을 사용하면 새로 생성 된 스레드에서 Call () 메소드의 리턴 값을 얻을 수 있습니다.
이 프로그램을 실행 한 후에는 Sum = 4950이 항상 마지막 출력임을 알 수 있습니다. "루프의 기본 스레드가 실행되었습니다 ..."는 어린이 스레드 루프 중간에 출력 될 가능성이 높습니다. CPU의 스레드 스케줄링 메커니즘에서 "루프의 기본 스레드가 실행되었습니다 ..."의 출력 타이밍에 문제가 없다는 것을 알고 있습니다. 왜 합계 = 4950이 영원히 출력 될까요?
그 이유는 ft.get () 메소드를 통해 Child Thread의 Call () 메소드가 얻어지면 HILD 스레드의 메소드가 아직 실행되지 않았을 때 ft.get () 메소드가 반환 값을 얻기 전에 Call () 메소드가 실행될 때까지 차단되기 때문입니다.
위의 내용은 주로 세 가지 공통 스레드 생성 방법을 설명합니다. 스레드의 시작을 위해서는 모두 스레드 객체의 시작 () 메소드라고합니다. 동일한 스레드 객체에서 start () 메소드를 두 번 호출 할 수 없다는 점에 유의해야합니다.
III. Java Multithreading의 준비, 실행 및 죽음 상태
준비 상태는 실행중인 상태로 변환됩니다.이 스레드가 프로세서 리소스를 가져 오면;
실행 상태는 준비 상태로 변환됩니다.이 스레드가 수율 () 메소드를 적극적으로 호출하거나 실행 중에 프로세서 리소스를 잃을 때.
실행 상태는 죽은 상태로 변환됩니다. 스레드 실행 본체가 완료되거나 예외가 발생합니다.
여기서 스레드의 수율 () 메소드가 호출되면 스레드가 실행 상태에서 준비 상태로 전환되지만 CPU의 준비 상태에있는 스레드는 특정 임의성을 갖는다는 점에 유의해야합니다. 따라서 A 스레드가 수율 () 메소드를 호출 한 후에도 CPU가 여전히 A 스레드를 예약하는 것이 발생할 수 있습니다.
실제 비즈니스 요구로 인해 스레드를 특정 기회에서 종료 해야하는 경우가 종종 발생합니다. 현재 가장 일반적인 방법은 부울 변수를 설정하는 것입니다. 조건이 충족되면 스레드 실행 본체가 빠르게 실행됩니다. 좋다:
공개 클래스 스레드 테스트 {public static void main (string [] args) {myrunnable myrunnable = new myrunnable (); 스레드 스레드 = 새 스레드 (myrunnable); for (int i = 0; i <100; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); if (i == 30) {thread.start (); } if (i == 40) {myRunnable.stopThread (); }}}} 클래스 myrunnable 구현 런닝 가능한 {private boolean stop; @override public void run () {for (int i = 0; i <100 &&! spore; i ++) {system.out.println (thread.currentthread (). getName () + "" + i); }} public void stopthread () {this.stop = true; }}우리는 앞으로 관련 기사를 계속 정리할 것입니다. 이 사이트를 지원 해주셔서 감사합니다!
일련의 기사 :
Java 다중 스레드 인스턴스의 설명 (i)
Java 다중 스레드 인스턴스에 대한 자세한 설명 (II)
Java 다중 스레드 인스턴스에 대한 자세한 설명 (III)