오늘 우리는 봄에 비동기 프로그래밍을 수행하는 방법을 배울 것입니다. 우리는 웹 서버가 request 스레드가 스레드 풀에서 얻는 스레드가 스레드 풀에서 얻어진다는 것을 알고 있습니다. 웹 요청 수가 매우 크면 요청이 들어올 때 처리 스레드를 생성하는 방법이 있기 때문에 설명하기가 어렵지 않습니다. 스레드 및 스레드 컨텍스트 스위칭의 오버 헤드가 비교적 크기 때문에 웹 서버는 결국 충돌에 직면합니다. 또한 웹 서버에서 만든 처리 스레드는 기본적으로 처음부터 끝까지 동기식으로 실행됩니다. 즉, 처리 스레드 A를 처리 요청 B를 처리하는 경우 B가 return 되지 않으면 처리 스레드 A는 다른 요청을 처리하기 위해 탈출 할 수 없으므로 웹 서버의 동시 처리 기능을 크게 제한합니다.
따라서 스레드 풀은 스레드 재활용 문제를 해결하여 동기식 처리 요청을 해결하는 방법은 무엇입니까? 대답은 비동기 처리입니다. 비동기 처리 란 무엇입니까? 비동기 처리는 주로 위의 요청 처리가 완료되기 전에 위의 B 요청이 유휴 상태가되며 다른 요청을 계속 처리하도록 스레드 A를 해제 할 수 있습니다. 그런 다음이 작업을 수행하고 스레드 A의 스레드 C를 다시 시작하여 작업을 실행하고 웹 서버로 직접 돌아오고 새 요청을 계속 수락합니다.
아래 설명을 시작하기 전에 여기에서 두 가지 개념을 구별 할 것입니다.
1. 프로세스 스레드
처리 스레드는 웹 서버에 속하며 사용자 요청 처리를 담당하며 스레드 풀에서 관리합니다.
2. 비동기 스레딩
비동기 스레드는 사용자 정의 스레드이며 스레드 풀에서 관리 할 수 있습니다.
Spring은 비동기 작업을 지원합니다. 비동기 작업은 WebAsyncTask 클래스를 사용하여 구현할 수 있습니다. 동시에 작업 시간이 초과 될 때 처리하는 방법 및 예외를 던지는 방법과 같은 비동기 작업에 해당하는 콜백 처리를 설정할 수도 있습니다. 비동기 작업은 일반적으로 매우 실용적입니다. 예를 들어, 우리는 오랫동안 처리 될 수있는 작업을 비동기식 스레드로 처리하거나 주문이 지불되면 비동기 작업이 주문의 지불 결과를 쿼리 할 수 있도록합니다.
1. 정상적인 비동기 작업
시연 편의를 위해 비동기 작업의 실행은 Thread.sleep(long) 사용하여 시뮬레이션됩니다. 이제 사용자가 다음 인터페이스를 요청한다고 가정합니다.
http://localhost:7000/demo/getUserWithNoThing.json
비동기 작업 인터페이스는 다음과 같이 정의됩니다.
/*** 예외없이 테스트 비동기 작업*/@requestMapping (value = "getUserwithNothing.json", method = requestmethod.get) public webasynctask <string> getUserwithNothing () {// 인쇄 스레드 이름 System.err.println ( "메인 스레드 이름은" + Thread.currentShread (). // 이것은 10S WebAsyncTask <string> task1 = new WebAsyncTask <string> (10 * 1000l, () -> {System.err.println ( "첫 번째 스레드 이름은" + 스레드. 1000l); 반환 "작업 1은 성공적으로 실행됩니다! 예외는 발생하지 않습니다!"; // 작업 실행이 완료 될 때 메소드가 호출됩니다. task1.onCompleTion (() -> {System.err.println ( "작업 1이 완료된!");}); System.err.println ( "Task1은 다른 것들을 계속 처리합니다!"); return task1;}콘솔은 다음과 같이 인쇄합니다.
기본 스레드 이름은 HTTP-NIO-7000-EXEC-1입니다
Task1은 다른 것들을 계속 다루고 있습니다!
첫 번째 스레드 이름은 mvcasync1입니다
작업 1이 완료되었습니다!
브라우저 결과는 다음과 같습니다.
2. 예외 비동기 작업을 초과합니다
인터페이스 호출 : http://localhost:7000/demo/getUserWithError.json
/*** 오류가 발생하는 비동기 작업* @return*/ @requestMapping (value = "value ="getUserWithError.json ", method = requestMethod.get) public webasynctask <string> getUserWithError () {System.err.println ("메인 스레드 이름은 " + Thread.CurrentThread ().); 비동기적인 작업. webasynctask <string> task3 = new Webasynctask <string> (10 * 1000l, () -> {System.err.println (두 번째 스레드 이름은 " + strook.currentThread (). getName ()); // 예외적 인 int num = 9/ 0; system.err.println (num); task3.onerror (() -> {System.err.println ( "============================================================================================================================================== =============================================================================================================== =============================================================================================================== ===================================================================================================================================== "============================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== ===========================================================================콘솔 출력은 다음과 같습니다.
기본 스레드 이름은 HTTP-NIO-7000-EXEC-1입니다
Task3는 다른 것들을 계속 다루고 있습니다!
두 번째 스레드 이름은 mvcasync1입니다
2018-06-15 09 : 40 : 40 : 13.538 오류 9168 --- [NIO-7000-EXEC-2] OACCC [.java.lang.arithmeticexception : / by zero
at com.example.demo.controller.getuserinfocontroller.lambda $ 5 (getuserinfocontroller.java:93) ~ [클래스/: na]
org.springframework.web.context.request.async.webasyncmanager.lambda $ startCallableProcessing $ 4 (webasyncmanager.java:317) ~ [Spring-web-5.0.6. Release.jar : 5.0.6.release]
at java.util.concurrent.executors $ runnableadapter.call (Executors.java:511) ~ [NA : 1.8.0_161]
at java.util.concurrent.futuretask.run (futuretask.java:266) ~ [NA : 1.8.0_161]
at java.lang.thread.run (Thread.java:748) [NA : 1.8.0_161]2018-06-15 09 : 40 : 13.539 오류 9168 --- [NIO-7000-Exec-2] OACCC [. 중첩 예외는 java.lang.arithmeticexception : / by zero]입니다.
java.lang.arithmeticexception : / by zero
at com.example.demo.controller.getuserinfocontroller.lambda $ 5 (getuserinfocontroller.java:93) ~ [클래스/: na]
org.springframework.web.context.request.async.webasyncmanager.lambda $ startCallableProcessing $ 4 (webasyncmanager.java:317) ~ [Spring-web-5.0.6. Release.jar : 5.0.6.release]
at java.util.concurrent.executors $ runnableadapter.call (Executors.java:511) ~ [NA : 1.8.0_161]
at java.util.concurrent.futuretask.run (futuretask.java:266) ~ [NA : 1.8.0_161]
at java.lang.thread.run (Thread.java:748) [NA : 1.8.0_161]================================================================================================================================
미션 3이 발생했습니다!
작업 3이 완료되었습니다!
물론, 사용자의 의견에 비우호적 인 것을 피하기 위해 위의 예외 처리를 수행 할 수도 있습니다. 예외 처리는 스프링 부츠/스프링 통합 오류 처리 체계 사용에 관한 내 기사에서 다른 기사를 확인할 수 있습니다.
브라우저 출력 결과 :
3. 시간 초과 비동기 작업
인터페이스 호출 : http://localhost:7000/demo/getUserWithTimeOut.json
/*** 작업이 시간을 초과하는 비동기 작업* @return*/ @requestMapping (value = "getUserwithTimeout.json", Method = requestMethod.get) public webasynctask <string> getUserwitHtimeout () {System.err.println ( "메인 스레드 이름은" + thread.currentthread ().); // 이것은 10S WebasyncTask <string> task2 = 새로운 webasynctask <string> (10 * 1000l, () -> {system.err.println ( "두 번째 스레드 이름은" + 스레드 .currentthread (). getname ()); thread.stimeout (20 * 1000l); // 작업 시간 초과는이 메소드를 호출합니다. task2.ontimeout (() -> { System.err.println ( "=================================================================================================================== ===================================================================================================================================== ===================================================================================================================================== ===================================================================================================================================== "============================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== ===========================================================================콘솔 실행 결과 :
기본 스레드 이름은 HTTP-NIO-7000-EXEC-4입니다
Task2는 다른 것들을 계속 다루고 있습니다!
두 번째 스레드 이름은 mvcasync2입니다
=========================================================================================================================================
작업 2가 완료되었습니다!
브라우저 실행 결과 :
4. 스레드 풀 비동기 작업
위의 세 가지 경우의 비동기 작업은 기본적으로 스레드 풀 메커니즘에 의해 관리되지 않습니다. 즉, 요청이 들어 오면 처리 스레드가 릴리스되지만 시스템은 여전히 각 요청에 대해 비동기 작업 스레드를 생성합니다. 이는 위에서 본 것처럼 MvcAsync 로 시작하는 비동기 작업 스레드입니다. 즉, 이것은 작동하지 않을 것입니다. 오버 헤드가 특히 높습니다! 따라서 관리에 스레드 풀을 사용하고 WebAsyncTask 클래스 생성자에서 ThreadPoolTaskExecutor 객체 인스턴스를 직접 통과 할 수 있습니다.
위의 첫 번째 사례에서 동시 요청을 수행 할 때 발생하는 일을 먼저 살펴 보겠습니다 (여기서는 http://localhost:7000/demo/getUserWithNoThing.json 에 대한 동시 호출을 시뮬레이션합니다) :
콘솔 출력은 다음과 같습니다.
첫 번째 스레드 이름은 MVCASYNC57입니다
첫 번째 스레드 이름은 mvcasync58입니다
첫 번째 스레드 이름은 MVCASYNC59입니다
첫 번째 스레드 이름은 mvcasync60입니다
첫 번째 스레드 이름은 mvcasync61입니다
첫 번째 스레드 이름은 mvcasync62입니다
첫 번째 스레드 이름은 mvcasync63입니다
첫 번째 스레드 이름은 mvcasync64입니다
첫 번째 스레드 이름은 mvcasync65입니다
첫 번째 스레드 이름은 mvcasync66입니다
첫 번째 스레드 이름은 mvcasync67입니다
첫 번째 스레드 이름은 mvcasync68입니다
첫 번째 스레드 이름은 mvcasync69입니다
첫 번째 스레드 이름은 mvcasync70입니다
첫 번째 스레드 이름은 mvcasync71입니다
첫 번째 스레드 이름은 mvcasync72입니다
첫 번째 스레드 이름은 MVCASYNC73입니다
첫 번째 스레드 이름은 MVCASYNC74입니다
첫 번째 스레드 이름은 mvcasync76입니다
첫 번째 스레드 이름은 MVCASYNC75입니다
첫 번째 스레드 이름은 MVCASYNC77입니다
첫 번째 스레드 이름은 mvcasync78입니다
첫 번째 스레드 이름은 MVCASYNC79입니다
첫 번째 스레드 이름은 mvcasync80입니다
스레드 풀이 추가되지 않으므로 100 개의 요청이 100 개의 비동기 작업 스레드를 열면 특히 비싸고 권장되지 않습니다.
다음은 스레드 풀의 구현입니다.
인터페이스 호출 : http://localhost:7000/demo/getUserWithExecutor.json
/*** 테스트 스레드 풀* @return*/ @requestMapping (value = "getUserWithExecutor.json", method = requestMethod.get) public webasynctask <string> getUserWitHexeCutor () {System.err.println ( "메인 스레드 이름은" + 스레드 .CurrentThread (). // 이것은 비동기 작업을 시작하도록 시뮬레이션되며 스레드 풀이 여기에 전달됩니다. webasynctask <string> task1 = 새로운 webasynctask <string> (10 * 1000l, executor, () -> {system.err.println ( "첫 번째 스레드 이름은" + thread.currentThread (). getName ()); thread.slee (5000L); return "task 4 성공적으로 성공했습니다!";}); // 작업 실행이 완료되면이 메소드를 호출합니다. task1.oncompletion (() -> {System.err.println ( "작업 4가 완료된!");}); System.err.println ( "Task4는 다른 것들을 계속 처리합니다!"); return task1;}스레드 풀은 다음과 같이 정의됩니다.
@ConfigurationPublic Class MyExecutor {@bean public static strandpooltaskexecutor getExecutor () {ThreadPooltasKexeCutor taskexecutor = new ThreadPoolTasKexEcutor (); taskexecutor.setcorepoolsize (30); taskexecutor.setmaxpoolsize (30); taskexecutor.setqueuecapacity (50); taskexecutor.setthreadnameprefix ( "huang"); // 비동기 작업 스레드 이름은 Huang Prefix return taskexecutor; }}위의 동시 테스트는 다음과 같은 결과를 얻는 데 사용될 수 있습니다.
이 기사의 샘플 코드 주소 : https://github.com/smallercoder/webasynctask
스레드 풀을 사용하면 서버 리소스를 저장하고 서버 처리 기능을 최적화 할 수 있습니다. 자주 사용해야합니다! 읽어 주셔서 감사합니다! 도움이 될 것이라고 생각되면 시작하십시오!
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.