วันนี้เราจะได้เรียนรู้วิธีการเขียนโปรแกรมแบบอะซิงโครนัสในฤดูใบไม้ผลิ เราทุกคนรู้ว่าเธรดที่เว็บเซิร์ฟเวอร์ประมวล request คำขอได้มาจากพูลเธรดซึ่งไม่ยากที่จะอธิบายเพราะเมื่อจำนวนคำขอเว็บมีขนาดใหญ่มากวิธีการสร้างเธรดการประมวลผลเมื่อมีการร้องขอเข้ามาเนื่องจากค่าใช้จ่ายในการสร้างเธรดและการสลับบริบทของเธรดนั้นค่อนข้างใหญ่ นอกจากนี้เธรดการประมวลผลที่สร้างโดยเว็บเซิร์ฟเวอร์จะถูกเรียกใช้งานแบบซิงโครนัสตั้งแต่ต้นจนจบโดยค่าเริ่มต้น กล่าวคือหากการประมวลผลเธรด A รับผิดชอบการประมวลผลคำขอ B ดังนั้นเมื่อ B ไม่ return การประมวลผลเธรด A ไม่สามารถหลบหนีไปยังการดำเนินการตามคำขออื่น ๆ ซึ่งจะจำกัดความสามารถในการประมวลผลพร้อมกันของเว็บเซิร์ฟเวอร์ได้อย่างมาก
ดังนั้นพูลเธรดจะแก้ปัญหาการรีไซเคิลเธรดดังนั้นจะแก้คำขอการประมวลผลแบบซิงโครนัสได้อย่างไร? คำตอบคือการประมวลผลแบบอะซิงโครนัส การประมวลผลแบบอะซิงโครนัสคืออะไร? การประมวลผลแบบอะซิงโครนัสส่วนใหญ่อนุญาตให้คำขอ B ข้างต้นไม่ได้ใช้งานก่อนที่การประมวลผลคำขอข้างต้นจะเสร็จสมบูรณ์และเธรด A สามารถปล่อยให้เป็นอิสระเพื่อดำเนินการตามคำขออื่น ๆ ต่อไป จากนั้นเราสามารถทำสิ่งนี้รีสตาร์ทเธรด C ภายในเธรด A เพื่อดำเนินการงานให้ส่งคืนไปยังเว็บเซิร์ฟเวอร์โดยตรงและดำเนินการตามคำขอใหม่ต่อไป
ก่อนที่จะเริ่มคำอธิบายด้านล่างฉันจะแยกแยะแนวคิดสองแนวคิดก่อน:
1. ประมวลผลเธรด
เธรดการประมวลผลเป็นของเว็บเซิร์ฟเวอร์รับผิดชอบการประมวลผลคำขอของผู้ใช้และได้รับการจัดการโดยพูลเธรด
2. เกลียวแบบอะซิงโครนัส
เธรดแบบอะซิงโครนัสเป็นเธรดที่ผู้ใช้กำหนดและสามารถจัดการได้โดยพูลเธรด
ฤดูใบไม้ผลิให้การสนับสนุนงานอะซิงโครนัส สามารถใช้งานแบบอะซิงโครนัสได้โดยใช้คลาส WebAsyncTask ในเวลาเดียวกันเรายังสามารถตั้งค่าการประมวลผลการโทรกลับที่สอดคล้องกันสำหรับงานอะซิงโครนัสเช่นวิธีจัดการเมื่องานหมดเวลาและวิธีการโยนข้อยกเว้น งานอะซิงโครนัสมักจะใช้งานได้จริงมาก ตัวอย่างเช่นเราต้องการออกจากการดำเนินการที่อาจดำเนินการเป็นเวลานานกับเธรดอะซิงโครนัสเพื่อดำเนินการหรือเมื่อมีการชำระคำสั่งซื้อเราเปิดใช้งานงานอะซิงโครนัสเพื่อสอบถามผลการชำระเงินของคำสั่งซื้อ
1. งานแบบอะซิงโครนัสปกติ
เพื่อความสะดวกในการสาธิตการดำเนินงานแบบอะซิงโครนัสจะถูกจำลองโดยใช้ Thread.sleep(long) ตอนนี้สมมติว่าผู้ใช้ร้องขออินเทอร์เฟซต่อไปนี้:
http://localhost:7000/demo/getUserWithNoThing.json
อินเทอร์เฟซงานแบบอะซิงโครนัสถูกกำหนดดังนี้:
/*** ทดสอบงานแบบอะซิงโครนัสโดยไม่มีข้อยกเว้นใด ๆ*/@requestmapping (value = "getUserWithNothing.json", method = requestMethod.get) สาธารณะ webasynctask <String> getUserWithNothing () {// // พิมพ์ชื่อเธรด // สิ่งนี้จำลองการเปิดงานแบบอะซิงโครนัสด้วยการหมดเวลาของ 10S webasynctask <string> task1 = new webasynctask <string> (10 * 1000L, () -> {system.err.println ("ชื่อเธรดแรกคือ" thread.currentthread () 1000L); // วิธีการถูกเรียกเมื่อการดำเนินการงานเสร็จสิ้น task1.oncompletion (() -> {system.err.println ("งาน 1 ดำเนินการเสร็จสมบูรณ์!");}); System.err.println ("task1 ยังคงจัดการกับสิ่งอื่น ๆ !"); ส่งคืน task1;}คอนโซลพิมพ์ดังนี้:
ชื่อเธรดหลักคือ HTTP-NIO-7000-EXEC-1
TASK1 ยังคงจัดการกับสิ่งอื่น ๆ !
ชื่อเธรดแรกคือ mvcasync1
ภารกิจที่ 1 เสร็จสมบูรณ์แล้ว!
ผลของเบราว์เซอร์มีดังนี้:
2. เกินกว่างานอะซิงโครนัส
การโทรอินเตอร์เฟส: http://localhost:7000/demo/getUserWithError.json
/*** ทดสอบงานอะซิงโครนัสที่เกิดข้อผิดพลาด* @return*/ @requestmapping (value = "getUserWithERROR.json", method = requestMethod.get) public WebAsynctask <String> getUserWithERROR () {system.err.println ( งาน. webasynctask <string> task3 = ใหม่ webasynctask <string> (10 * 1000l, () -> {system.err.println ("ชื่อเธรดที่สองคือ" + thread.currentthread (). getName ()); - {system.err.println ("===================================================================================================== - - - - - - - - - - -เอาต์พุตคอนโซลมีดังนี้:
ชื่อเธรดหลักคือ HTTP-NIO-7000-EXEC-1
Task3 ยังคงจัดการกับสิ่งอื่น ๆ !
ชื่อเธรดที่สองคือ mvcasync1
2018-06-15 09: 40: 13.538 ข้อผิดพลาด 9168 --- [NIO-7000-Exec-2] OACCC [. [. [. [. [. Dispatcherservlet]: Servlet.Service () สำหรับ Servlet [Dispatcherservlet]java.lang.arithmeticexception: / By Zero
ที่ 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]
ที่ java.util.concurrent.executors $ runnableadapter.call (Executors.java:511) ~ [NA: 1.8.0_161]
ที่ java.util.concurrent.futuretask.run (FutureTask.java:266) ~ [NA: 1.8.0_161]
ที่ 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 [. [. [. [. [dispatcherservlet]: servlet.service () สำหรับ servlet [dispatcherservlet] ในบริบทที่มีเส้นทาง [/demo] ข้อยกเว้นที่ซ้อนกันคือ java.lang.arithmeticexception: / โดยศูนย์] ด้วยสาเหตุที่แท้จริง
java.lang.arithmeticexception: / By Zero
ที่ 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]
ที่ java.util.concurrent.executors $ runnableadapter.call (Executors.java:511) ~ [NA: 1.8.0_161]
ที่ java.util.concurrent.futuretask.run (FutureTask.java:266) ~ [NA: 1.8.0_161]
ที่ 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) WebAsynctask สาธารณะ <String> getUserWithTimeOut () {system.err.println ("ชื่อหลักคือ" // นี่คือการจำลองเพื่อเริ่มงานแบบอะซิงโครนัสหมดเวลาของ 10S webasynctask <String> task2 = ใหม่ webasynctask <String> (10 * 1000L, () -> {System.err.println ("ชื่อเธรดที่สองคือ" thread.currentthread () // งานหมดเวลาเรียกใช้วิธีนี้ task2.ontimeout (() -> { System.err.println ("================================================================================================ - - - - - - - - - - -ผลการดำเนินการคอนโซล:
ชื่อเธรดหลักคือ HTTP-NIO-7000-EXEC-4
Task2 ยังคงจัดการกับสิ่งอื่น ๆ !
ชื่อเธรดที่สองคือ mvcasync2
-
ภารกิจที่ 2 เสร็จสมบูรณ์แล้ว!
ผลการดำเนินการเบราว์เซอร์:
4. งานสระว่ายน้ำแบบอะซิงโครนัส
งานอะซิงโครนัสในสามกรณีข้างต้นไม่ได้รับการจัดการโดยกลไกพูลเธรดโดยค่าเริ่มต้น กล่าวคือหากมีการร้องขอเข้ามาแม้ว่าเธรดการประมวลผลจะถูกปล่อยออกมา แต่ระบบจะยังคงสร้างเธรดงานแบบอะซิงโครนัสสำหรับแต่ละคำขอซึ่งเป็นเธรดงานแบบอะซิงโครนัสที่เริ่มต้นด้วย MvcAsync ตามที่เราเห็นด้านบน นั่นคือสิ่งนี้จะไม่ทำงานค่าใช้จ่ายสูงเป็นพิเศษ! ดังนั้นเราสามารถใช้พูลเธรดสำหรับการจัดการและผ่านอินสแตนซ์วัตถุ ThreadPoolTaskExecutor โดยตรงในตัวสร้างคลาส WebAsyncTask
ก่อนอื่นให้ดูว่าจะเกิดอะไรขึ้นเมื่อดำเนินการตามคำขอพร้อมกันในกรณีแรกด้านบน (ที่นี่เราจำลองการโทรพร้อมกันไปที่ 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 = "getUserveTexecutor.json", method = requestMethod.get) สาธารณะ webAsynctask <String> getUserWithExecutor () {system.err.println ("ชื่อเธรดหลักคือ" // นี่คือการจำลองเพื่อเริ่มงานแบบอะซิงโครนัสและพูลเธรดจะผ่านไปที่นี่ WebAsyNCTASK <String> task1 = ใหม่ webAsynctask <String> (10 * 1000L, executor, () -> {system.err.println ("ชื่อเธรดแรกคือ" + thread.currentthread (). getName ()); // เรียกวิธีนี้เมื่อการดำเนินการงานเสร็จสิ้น task1.oncompletion (() -> {system.err.println ("งาน 4 ดำเนินการเสร็จสมบูรณ์!");}); System.err.println ("Task4 ยังคงจัดการกับสิ่งอื่น ๆ !"); ส่งคืน task1;}พูลเธรดถูกกำหนดดังนี้:
@ConfigurationPublic คลาส myexecutor {@bean สาธารณะคงที่ threadpooltaskexecutor getExecutor () {threadpooltaskexecutor taskexecutor = ใหม่ threadpooltaskexecutor (); Taskexecutor.SetCorePoolSize (30); Taskexecutor.setMaxPoolsize (30); taskexecutor.setqueUecapacity (50); taskexecutor.setThreadNamePrefix ("Huang"); // ชื่อด้ายงานแบบอะซิงโครนัสคือ Huang คำนำหน้าส่งคืน taskexecutor; -การทดสอบที่เกิดขึ้นพร้อมกันสามารถใช้เพื่อให้ได้ผลลัพธ์ต่อไปนี้:
ที่อยู่รหัสตัวอย่างของบทความนี้: https://github.com/smallercoder/webasynctask
การใช้พูลเธรดสามารถบันทึกทรัพยากรเซิร์ฟเวอร์และเพิ่มประสิทธิภาพความสามารถในการประมวลผลเซิร์ฟเวอร์ อย่าลืมใช้บ่อย! ขอบคุณสำหรับการอ่าน! หากคุณคิดว่ามันจะเป็นประโยชน์กับคุณโปรดเริ่ม!
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น