เทคนิคการสั่งให้ทำงานคู่ขนานในจาวา

วิธีพื้นฐานที่สุดในการสั่งให้ทำงานคู่ขนาน (concurrent programming) ในจาวาคือการใช้งานเธรด (Thread) ซึ่งต้องอาศัยการควบคุมด้วยซิงโครไนซ์ (synchronized) หรือล็อค (locking) ที่อาจจะเสี่ยงต่อการเกิดความผิดพลาดถ้าจัดการไม่ดี

บทความที่เจอมาได้กล่าวถึงวิธีการอื่นๆที่นำมาใช้แทนการเรียกใช้เธรดได้ และควบคุมได้ดีและง่ายกว่า รวมถึงพูดถึงเทคนิคในภาษาอื่นๆที่ทำงานบนเจวีเอ็ม (JVM: Java Virtual Machine) เช่น สกาลา (Scala) กรูวี่ (Groovy) และโคลเชอร์ (Clojure) อีกด้วย

  1. เอ็กซิคิวเตอร์เซอร์วิส (ExecutorService) เริ่มมีในจาวา 5 อย่างน้อยที่สุด วิธีนี้ก็เป็นวิธีทีี่ดีกว่าการเรียกใช้เธรดโดยตรง มีทั้งการใช้แฟคทรี่เม็ดเถิด newXXXPool() หรือจะควบคุมด้วยการใช้ ThreadPoolExecutor โดยตรง
  2. พาราแลลสตรีม (Parallel Stream) เริ่มมีในจาวา 8 ที่เปลี่ยนสตรีมธรรมดา (.stream()) ให้ทำงานแบบคู่ขนานได้ทันที (.parallelStream()) และยังทำงานร่วมกับ .findAny() เพื่อทำงานเดียวกันพร้อมกันแบบคู่ขนานแต่หยุดเมื่อได้ผลลัพธ์จากเธรดใดเธรดหนึ่งแล้ว แต่การใช้พาราแลลสตรีมไม่ได้รับประกันว่าจะประสิทธิภาพดีกว่าสตรีมธรรมดาเสมอไป
  3. คอมพลีเทเบิลฟิวเจอร์ (CompletableFuture) ฟิวเจอร์ (Future) เริ่มมีในจาวา 5 ซึ่งทำงานแบบบล็อกกิ้ง (blocking) กวาวา (Guava) นั้นมีลิสซึนเนเบิลฟิวเจอร์ (ListenableFuture) ที่ใช้งานแทนฟิวเจอร์แบบไม่บล็อก (non-blocking) จนกระทั่งคอมพลีเทเบิลฟิวเจอร์ออกมา โดยเรียก .supplyAsync() แทนการเรียก ExecutorService.submit()
  4. ฟอร์คจอยน์พูล (ForkJoinPool) เริ่มมีในจาวา 7 โดยใช้การกระจายงานแบ่งไปให้เธรดทำงานพร้อมกันแบบแยกกลุ่ม และนำผลลัพธ์มารวมกัน .fork() ใช้เพื่อแตกงานย่อย และ .join() เพื่อรอผลลัพธ์
  5. อาร์เอ๊กซ์จาวา (RxJava) เป็นโอเพ่นซอร์ส (Open Source) ที่พัฒนาต่อ (extends) จากฟิวเจอร์ โดยมีออบเซอร์เวเบิล (Observable) ซึ่งทำงานแบบไม่บล็อก ลักษณะการใช้งานเทียบได้กับการใช้ .stream() โดยเราไม่ต้องสนใจกลไกการสร้างเธรดภายใน

นี่เป็นเพียงบทความสั้นๆเพื่อให้เห็นวิธีต่างๆที่ไม่ต้องเข้าถึงเธรดโดยตรง เราคงต้องทดลองแต่ละวิธีเพื่อความเชี่ยวชาญ และจะได้เห็นข้อดีข้อเสียในการใช้งานจริง สามารถเข้าไปดูตัวอย่างซอร์สโค้ดได้จากในบทความ

ที่มา: https://community.oracle.com/docs/DOC-921264

สแลช (SLASH)