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

วิธีพื้นฐานที่สุดในการสั่งให้ทำงานคู่ขนาน (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)

7 วิธีใช้งาน Vi อย่างมีประสิทธิภาพ

คนเขียนโปรแกรมส่วนใหญ่เริ่มจากการใช้ไอดีอี (IDE: Integrated Development Environment) เช่น วิชวลสตูดิโอ (Visual Studio) หรือ เอคลิปส์ (Eclipse)  แต่เมื่อเวลาผ่านไป คอมพิวเตอร์มีประสิทธิภาพมากขึ้น ไอดีอีเหล่านี้ก็ใช้ทรัพยากรมากขึ้นตาม จนอาจจะใช้มากเกินความจำเป็น และบางครั้งไอดีอีแต่ละค่ายก็มีความสามารถที่โดดเด่นแตกต่างกัน ถ้าเลือกตัวหนึ่ง ก็จะไม่ได้ใช้อีกตัวหนึ่ง จึงต้องการหาไอดีอีตัวใหม่ที่ยืดหยุ่นกว่า ทั้งความสามารถและประสิทธิภาพ มาใช้งานทดแทน

อินเทลลิเจ ไอเดีย (IntelliJ IDEA) เป็นทางเลือกที่มาแรง (มาสักพักแล้ว) ในสายจาวา จนกูเกิล (Google) เลือกที่จะเอาไปพัฒนาต่อเป็นไอดีอีหลักในการพัฒนาแอปบนมือถือ นั่นคือแอนดรอยด์สตูดิโอ (Android Studio)

แต่ไหนๆจะเริ่มใหม่ทั้งทีก็เลยเกิดนึกอยากกลับไปใช้เท็กซ์เอดิเตอร์ (Text Editor) คงกระพันอย่างวีไอ (Vi) เพราะไม่ได้ใช้ทรัพยากรมาก และสามารถเพิ่มปลั๊กอินได้ในวีไอเอ็ม (Vim: Vi Improved) ศึกษาไปเรื่อยๆก็เห็นว่า ชุมชนคนใช้งานค่อนข้างคึกคัก จนเจอบทความหนึ่งน่าสนใจ จึงขอนำมาสรุปสั้นๆ เป็น “7 วิธีใช้งาน Vi อย่างมีประสิทธิภาพ” (7 habits of effective text editing)

  1. ย้ายเคอร์เซอร์ (cursor) ให้เร็วขึ้น
    • กระโดดไปคำที่ต้องการด้วยการค้นหา (/pattern)
    • ค้นหาซ้ำคำเดิมด้วยคำสั่ง *
    • เพิ่มออพชั่น incsearch เพื่อกระโดดไปคำที่เจอคำแรกทันที
    • เพิ่มออพชั่น hlsearch เพื่อเน้นคำที่ต้องการค้นหา
    • ไปวงเล็บปิดด้วยคำสั่ง %
    • หาบรรทัดที่ประกาศตัวแปรหรือฟังก์ชันด้วยคำสั่ง gd
  2. ไม่พิมพ์ข้อความเดิมซ้ำ
    • กด Ctrl-N เพื่อแสดงข้อความที่เคยพิมพ์ไปแล้ว คล้ายอินเทลลิเซนส์ (intellisense) ของวิชวลสตูดิโอ
    • คำสั่ง . จะเรียกคำสั่งล่าสุดซ้ำอีกครั้ง
    • ใช้มาโครช่วย
  3. หาตัวช่วยสำหรับความผิดพลาดที่เกิดขึ้นบ่อย
    • ใช้คำสั่ง abbr เพื่อย่อข้อความยาวๆให้สั้นลง เช่น :abbr psvm public static void main
    • เพิ่มออพชั่น syntax จะเห็นสีของข้อความที่เป็นคีย์เวิร์ดของแต่ละภาษาออกจากตัวแปรหรือชื่อฟังก์ชัน
  4. ทำงานพร้อมกันหลายไฟล์ในเซสชั่นเดียวกัน
    • ใช้วินโดว์หรือแท็บในการเปิดไฟล์พร้อมๆกัน
  5. ใช้คำสั่งภายนอกเพื่อลดการพิมพ์ข้อความ
    • ใช้คำสั่ง ! เพื่อเรียกคำสั่งของระบบปฏิบัติการ เช่น !wc -w เพื่อนับคำ !date เพื่อแทรกวันที่ปัจจุบัน
  6. จัดการพิมพ์ข้อความที่มีโครงสร้างตายตัว เช่น วงจรการเขียน คอมไพล์ และ แก้ไข
    • เปลี่ยน makeprg สำหรับแต่ละภาษา เช่น ใช้ mvn แทน javac
    • ถ้าเปลี่ยน makeprg ต้องตั้งค่า errorformat ด้วย เพื่อให้วีไอแสดงหน้าต่างควิกฟิกซ์ (Quickfix) และกระโดดไปยังตำแหน่งที่เกิดความผิดพลาดได้
  7. ทำให้เป็นนิสัย! เนื่องจากวีไอมีความสามารถมาก และไม่สามารถค้นหาจากเมนูได้เหมือนการใช้เมาส์ในไอดีอี จึงควรศึกษาเฉพาะบางความสามารถก็พอ เพราะการใช้งานวีไอต้องอาศัยความคุ้นเคยสูงมาก บางงานที่ไม่ค่อยได้ใช้ก็จะถูกลืม

บทความยังได้แนะนำ 3 ขั้นตอนที่ช่วยฝึกให้เป็นนิสัย

  1. สังเกตการใช้งานที่ซ้ำๆของตัวเองว่ามันใช้เวลานานเกินจำเป็นหรือไม่
  2. ถ้ามี วีไอมีความสามารถที่ตอบโจทย์หรือไม่
  3. ถ้ามี พยายามใช้งานจนชินมือ

การใช้งานวีไอที่ผ่านมา มักจะจบลงด้วยการที่รู้สึกว่ายังคุ้นเคยกับการใช้เมาส์ (mouse) มากกว่า แต่คราวนี้จะขอลองจริงจังอีกสักครั้งตามที่กล่าวไว้ในข้อ 7

ที่มา: http://www.moolenaar.net/habits.html

สแลช (slash)

เขียนจาวาให้ดีกว่าเดิมกันเถอะ

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

  1. ใส่ข้อมูลในคอนสตรักเตอร์ (constructor) แทนการสร้างจาวาบีน (Java Bean) เพราะทำให้โปรแกรมยาวทั้งตัวบีนและการเรียกใช้งาน
  2. ใช้บิลเดอร์ (builder) และการเชื่อมคำสั่งแทน (chaining) การใช้งานเซ็ตเตอร์ (setter) แบบจาวาบีน
  3. ใช้เอ็กเซ็พชั่น (exception) เมื่อจำเป็นเพื่อหลีกเลี่ยงการแคทช์ (catch) ที่ไม่จำเป็น
  4. ใช้ออพชันน่อล (Optional) ในจาวา 8 เมื่ออาจจะต้องคืนค่านัล (null)
  5. ใช้ไฟนอล (final) เพื่อทำให้ตัวแปรไม่โดนแก้ไขกลางทางโดยไม่ตั้งใจ
  6. หลีกเลี่ยงคลาสยูทิลิตี้ (utility class) ที่มีแต่สแตติกเม็ดเถิด (static method)
  7. ใช้สตรีม (stream) ในจาวา 8 เพื่อลดการเขียนที่ไม่จำเป็น

ส่วนอื่นๆก็เป็นเรื่องที่รู้โดยทั่วกันอยู่แล้ว เช่น ใช้เมเว่น (Maven) หรือเฟรมเวิร์ค (framework) ช่วยในการดีพลอย (deployment) ลดปัญหาความซ้ำซ้อนของไลบราลี่ (library dependency) ใช้ซีไอ (CI: Continuous Integration) ช่วยตรวจสอบ (analysis) ทดสอบ (test) แบบอัตโนมัติ การหาทูล (tools) มาช่วยเพิ่มประสิทธิภาพการทำงาน

ที่มา: https://github.com/cxxr/better-java

สแลช (slash)