1. Java로 멀티스레드 프로그램을 작성하는 것은 다른 프로그래밍 언어보다 훨씬 쉽습니다. 주로 Runnable 인터페이스와 Thread 클래스를 통해 구현됩니다.
publicclassSimpleRunnable implements Runnable{ private String message; publicstaticvoid main(String[] args) { SimpleRunnabler1 = new SimpleRunnable("Hello"); Threadt1 = new Thread(r1); t1.start(); for(;;){ System.out.println("Bye-bye"); } } public SimpleRunnable(String message){ this.message = message; } @Override publicvoid run() { for(;;){ System.out.println(message); } } }
위에서는 Runable 인터페이스를 상속받아 run()을 구현함으로써 멀티스레딩을 구현하였고, Thread를 이용하여 가상 CPU를 구현함으로써 스레드 r1이 독립적인 스레드에서 실행될 수 있도록 하였다. 사실 이 쓰레드와 메인 쓰레드는 완전히 독립된 쓰레드는 아니고, 대신 r1 쓰레드와 메인 쓰레드를 번갈아 가며 전환해 실행하는데, 전환 속도가 매우 빠르고 마치 두 개의 쓰레드가 독립적으로 실행되는 것처럼 보입니다.
2. 스레드 전환은 운영 체제에 따라 다릅니다.
스레드가 CPU를 점유하면 스레드 실행이 완료되거나 수동적으로 중지될 때까지 대기합니다. .
첫 번째는 우선순위 모드를 통해 우선순위가 가장 높은 스레드가 CPU를 먼저 가져옵니다.
하나는 타임 슬라이스입니다. 각 스레드는 타임 슬라이스를 실행한 후 종료되면 다른 스레드가 CPU를 점유할 수 있는 공정한 기회를 갖습니다.
Java의 스레드는 우선순위와 시간 분할을 기반으로 하는 포괄적인 접근 방식을 채택합니다. 구체적인 구현은 실행 중인 운영 체제에 따라 다릅니다. 예를 들어, 스레드가 타임 슬라이스 실행을 마치면 종료되고 우선 순위가 한 단계 낮아집니다. 그런 다음 우선 순위가 더 높은 스레드가 실행 프로세스 중에 우선 순위가 더 높은 스레드가 오면 CPU를 점유합니다. 현재 스레드를 점유합니다.
3, 스레드 실행 상태:
sleep(), wait(), suspend(), I/O 차단을 포함한 스레드 중지(Pause)
스레드 재시작( Run ) 포함, 절전 시간 초과, 통지(), 재개(), I/O 완료
스레드 종료, 중지()
스레드 대기, Join()
스레드가 CPU를 적극적으로 포기하고, Yield()
위의 suspens(),resume(),stop()은 더 이상 사용되지 않으며 더 이상 권장되지 않습니다.
4, sleep() 함수는 정적이며 객체가 아닌 클래스에 속하는 함수입니다. 이 함수는 다른 스레드를 중지하는 대신 호출 스레드를 특정 시간 동안 일시 중지하게 합니다. 다음과 같습니다
publicstaticvoidmain(String[] args)throwsException { SimpleRunnabler1 = new SimpleRunnable("Hello"); Threadt1 = newThread(r1); t1.start(); for(inti = 0; i < 10; i++){ System.out.println("Bye-bye"); } t1.sleep(10000); t1.stop(); }
위 코드는 t1을 10초 동안 중지하는 대신 메인 스레드를 10초 동안 중지합니다. 또한 sleep()으로 인해 스레드가 일시 중지되는 시간은 퍼지 값입니다. 위의 이론에 따르면 메인 스레드가 10초 동안 일시 중지됩니다. 그러나 스레드 전환의 불확실성으로 인해 메인 스레드는 일시 중지되지 않습니다. 정확히 10초.
5. 또 다른 정적 함수는 Yield()입니다. 이는 현재 실행 중인 스레드가 CPU를 적극적으로 포기한다는 것을 의미합니다. 이 함수는 위의 sleep() 함수와 유사하게 현재 스레드에서만 작동할 수 있습니다.
6. 프로그래밍은 효율적인 결과를 추구하고 멀티스레딩을 사용하는 것입니다. 그러나 멀티스레드 작업은 예측하기 어렵기 때문에 멀티스레드 작업의 결과를 최대한 예측 가능하게 만들기 위해 특정 방법을 사용하겠습니다.
class Thread1 extends Thread{ @Override publicvoid run(){ try{ System.out.println("thread1 start"); sleep(10000); // <3> System.out.println("thread1 finish");//<4> }catch(Exception e){ } } } class Thread2 extends Thread{ @Override publicvoid run(){ try{ System.out.println("thread2 start"); suspend(); // <2> System.out.println("thread2 finish");// <7> }catch(Exception e){ } } } publicclassThreadTest { publicstaticvoid main(String[] args) { Threadt1 = new Thread1(); Thread2t2 = new Thread2(); t1.start(); t2.start(); try{ System.out.println("s1"); t1.join(); // <1> System.out.println("s2"); // <5> t2.resume(); //<6> System.out.println("s3"); // <8> t2.join(); // <9> }catch(Exception e){ } System.out.println("s4"); // <10> } }
위 실행 중 하나의 결과는 다음과 같습니다.
thread1 start
thread2 start
s1
thread1 종료
s2
s3
thread2 Finish
s4
하지만 매번 이런 결과를 얻을 수는 없습니다. 그러나 그 중 일부는 예측 가능합니다. 어느 것이 예측 가능합니까? 예측할 수 없는 것은 무엇입니까?
(1) 처음 세 줄은 확실히 처음 세 줄을 차지합니다. <1> 코드가 메인 스레드를 중지하고 스레드 t1이 실행을 완료할 때까지 기다리고 t1 스레드가 스레드를 일시 중지합니다. 동시에 초에서 10초는 스레드 t2가 해당 스레드를 깨울 때까지 일시 중지된 상태에 있음을 의미합니다. 그렇지 않으면 스레드가 차단된 상태로 유지됩니다. 그러나 처음 세 줄의 출력 순서는 예측할 수 없습니다.
(2) 네 번째 줄은 확실히 네 번째 줄에 있을 것입니다. t1 sleep이 끝나면 먼저
(3) 다섯 번째 줄이 될 것입니다. t1 스레드의 실행이 끝나면 메인 스레드는 CPU가 <5>
코드 실행을 시작하도록 합니다. (4) 6번째와 7번째 라인의 위치는 바뀔 수 있습니다. 코드 <6>는 스레드 t2를 깨웁니다. 그런 다음 <7>에서 실행을 시작하고 메인 스레드는 계속해서 <8>
을 실행합니다. (5) 마지막 줄은 확실히 마지막 줄이 됩니다. <9>에서 메인 스레드를 일시 중지하고 t2가 끝날 때까지 기다린 다음 <10>을 실행하여 마지막 줄을 출력하면 메인 스레드가 끝나고 종료됩니다.