เมื่อเขียนซอฟต์แวร์คุณมักจะต้องใช้ฟังก์ชั่นบันทึกการพิมพ์ซึ่งสามารถช่วยคุณแก้ไขข้อบกพร่องและวางตำแหน่งปัญหา แต่เมธอดดั้งเดิมของ Java.out.println () ไม่ค่อยใช้ในการพัฒนาโครงการจริงและแม้แต่เครื่องมือตรวจสอบรหัสเช่น FindBugs จะคิดว่าการใช้ System.out.println () เป็นข้อผิดพลาด
ทำไม System.out.println () ซึ่งเป็นสิ่งประดิษฐ์สามเณรของ Java จะถูกปฏิเสธในการพัฒนาโครงการจริง ในความเป็นจริงตราบใดที่คุณวิเคราะห์อย่างระมัดระวังคุณจะพบข้อเสียมากมายของมัน ตัวอย่างเช่นหากไม่ได้ควบคุมบันทึกทั้งหมดจะถูกพิมพ์ตามปกติหลังจากเปิดตัวโครงการซึ่งจะช่วยลดประสิทธิภาพการทำงาน คุณจะแยกแยะประเภทใดที่บันทึกนี้พิมพ์ใน
ผู้นำของคุณไม่ใช่คนโง่ อย่างไรก็ตามผู้นำของคุณค่อนข้างดีและไม่อนุญาตให้คุณได้รับเครื่องมือบันทึก Niubi ด้วยฟังก์ชั่นต่าง ๆ ในตอนแรกเท่านั้น
ความต้องการนี้ไม่ยากสำหรับคุณ
Public Class LogUtil {Public Final Into Debug = 0; System.out.println (msg);}} ข้อมูลโมฆะสาธารณะ (String msg) {ถ้า (info> = ระดับ) {system.out.println (msg);} โมฆะสาธารณะ ing msg) {ถ้า (ข้อผิดพลาด> = ระดับ) {system.out.println (msg);}}}
พิมพ์บันทึกผ่านคลาสนี้และจำเป็นต้องควบคุมระดับของระดับเพื่อควบคุมเนื้อหาการพิมพ์ได้อย่างอิสระ ตัวอย่างเช่นโครงการอยู่ในขั้นตอนการพัฒนาและระดับถูกตั้งค่าให้ดีบักเพื่อให้ข้อมูลบันทึกทั้งหมดจะถูกพิมพ์ หากโครงการออนไลน์คุณสามารถตั้งค่าระดับเป็นข้อมูลเพื่อให้คุณสามารถดูบันทึกและการพิมพ์บันทึกระดับด้านบนเท่านั้น หากคุณต้องการดูบันทึกผิดคุณสามารถตั้งค่าระดับเป็นข้อผิดพลาดได้ และหากโครงการที่คุณพัฒนาเป็นเวอร์ชันไคลเอนต์คุณไม่ต้องการพิมพ์บันทึกใด ๆ คุณสามารถตั้งค่าระดับเป็นอะไรได้ คุณจะต้องโทรเมื่อพิมพ์:
ใหม่ logutil ()
คุณไม่สามารถรอที่จะแนะนำเครื่องมือนี้ให้กับผู้นำของคุณ
แต่มันใช้เวลาไม่นานสำหรับผู้นำของคุณที่จะหาคุณให้ข้อเสนอแนะ เขาบอกว่าถึงแม้ว่าเครื่องมือนี้จะใช้งานง่าย แต่ก็ไม่ได้แยกแยะระหว่างการพิมพ์สิ่งต่าง ๆ ใช้เพื่อใช้งาน
คุณคิดว่าผู้นำของคุณมีเหตุผลมากและคุณกำลังพยายามใช้ประโยชน์จากโอกาสนี้ในการฝึกโหมดการออกแบบดังนั้นคุณจึงเขียนรหัสต่อไปนี้ (PS: รหัสที่นี่ทำด้วยตัวเองและฉันไม่ได้สนใจ มันไม่ได้ให้ความสนใจกับมัน
LogUtil ระดับสาธารณะ {Private LogUtil LogUtilinStance; getInstance () {ถ้า (logutilInstance == null) {logutilInstance = new logUtil ();} ส่งคืน logutilInstance;} การดีบักโมฆะสาธารณะ (String g. {if (debug> = ระดับ) {system.out.println (msg);}; } ข้อมูลโมฆะสาธารณะ (String msg) {if (info> = ระดับ) {system.out.println (msg);} ข้อผิดพลาดโมฆะสาธารณะ (String msg) {ถ้า (ข้อผิดพลาด> = ระดับ) {System .OUT );}} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {logutil.getInstance ()
ก่อนอื่นตัวสร้างของ Logutil ได้รับการแปรรูปเพื่อไม่ให้ใช้คำหลักใหม่เพื่อสร้างอินสแตนซ์ logutil จากนั้นใช้ตัวแปรสแตติกส่วนตัวของสโลแกนเพื่อบันทึกอินสแตนซ์และจัดเตรียมวิธีการของ GetInstance สาธารณะเพื่อรับอินสแตนซ์ logutil สโลแกนโดยตรง สิ่งนี้สามารถมั่นใจได้ว่าจะมีเพียงอินสแตนซ์ของ logutil ในหน่วยความจำ โหมดเดี่ยวเสร็จสมบูรณ์! ในเวลานี้รหัสของบันทึกการพิมพ์จะต้องเปลี่ยนเป็นวิธีต่อไปนี้:
logutil.getInstance ()
คุณแสดงเวอร์ชันนี้ให้กับผู้นำของคุณ
คุณเต็มไปด้วยความสงสัยไม่มีโหมดตัวอย่างเดียวที่รับรู้เช่นนี้หรือไม่? บั๊กสามารถอะไรได้บ้าง?
ผู้นำของคุณแจ้งให้คุณทราบว่าการใช้โหมดซิงเกิ้ลคือการทำให้คลาสนี้มีเพียงอินสแตนซ์เดียวในหน่วยความจำ แต่คุณพิจารณาสถานการณ์ของบันทึกการพิมพ์ในหลายทเธดดเดอร์หรือไม่? ดังที่แสดงในรหัสต่อไปนี้:
public Static LogUtil getInstance () {ถ้า (logutilInstance == null) {logutilInstance = ใหม่ logUtil ();} ส่งคืน logutilinstance;}
หากมีสองเธรดในเวลาเดียวกันการดำเนินการวิธี GetInstance ในเวลาเดียวกันเธรดแรกเพียงแค่เรียกใช้บรรทัดที่สองและยังไม่ได้ดำเนินการบรรทัดที่สาม ด้วยวิธีนี้โหมดซิงเกิ้ลของคุณล้มเหลวเนื่องจากมีการสร้างอินสแตนซ์ที่แตกต่างกันสองแบบ
ทันใดนั้นคุณก็รู้ แต่ความคิดของคุณเร็วมากและคุณคิดว่าจะแก้ปัญหาได้ทันที
public synchronized logutil getInstance () {ถ้า (logutilinstance == null) {logutilInstance = new logUtil ();} ส่งคืน logutilinstance;}
ด้วยวิธีนี้มีเพียงเธรดเดียวเท่านั้นที่ได้รับอนุญาตให้เรียกใช้รหัสใน GetInstance ในเวลาเดียวกันซึ่งจะช่วยแก้สถานการณ์ได้อย่างมีประสิทธิภาพซึ่งทั้งสองอินสแตนซ์จะสร้างขึ้นข้างต้น
ผู้นำของคุณอ่านรหัสใหม่ของคุณและพูดว่า "ใช่แล้วสิ่งนี้จะแก้สถานการณ์ที่อาจสร้างสองอินสแตนซ์ แต่รหัสนี้ยังคงเป็นปัญหา"
คุณรู้สึกประหม่าทำไมมีปัญหาอะไรบ้าง?
ผู้นำของคุณยิ้ม: "อย่ากังวลคราวนี้มันไม่ใช่ข้อผิดพลาด แต่มันสามารถปรับให้เหมาะสมในแง่ของประสิทธิภาพดูถ้าคุณเพิ่มวิธีการซิงโครไนซ์ลงในวิธี getInstance ทุกครั้งที่ฉันไปที่ GetInstace วิธีการฉันจะซิงโครไนซ์
ก่อนอื่นให้ลบคำหลักที่ซิงโครไนซ์ออกจากคำสั่ง Method และเพิ่มลงใน Body Method:
public Static LogUtil getInstance () {ถ้า (logutilinstance == null) {ซิงโครไนซ์ (logutil.class) {ถ้า (logutilinstance == null) {// อาจจำเป็นเพราะทั้งสองกระบวนการอาจแนบในเวลาเดียวกันในเวลาเดียวกันในเวลาเดียวกัน เวลาในเวลาเดียวกัน
หลังจากเปลี่ยนรหัสเป็นสิ่งนี้มันจะเข้าสู่บรรทัดที่สามเมื่อสโลแกนไม่ได้เริ่มต้นแล้วเพิ่มการล็อคแบบซิงโครนัส ทันทีที่สโลแกนเริ่มต้นมันจะไม่ไปที่บรรทัดที่สามอีกต่อไปเพื่อให้วิธีการ getInstance จะไม่ได้รับผลกระทบจากการเชื่อมโยงการเชื่อมต่อและประสิทธิภาพจะได้รับการปรับปรุงในระดับหนึ่ง
คุณไม่สามารถช่วยได้ แต่ชื่นชม
ผู้นำของคุณเริ่มอ่อนน้อมถ่อมตนทันที: "วิธีนี้เรียกว่าการล็อคแบบตรวจสอบสองครั้ง แต่ฉันไม่คิดว่าคุณสามารถตรวจสอบข้อมูลเพิ่มเติมบนอินเทอร์เน็ตได้"
อันที่จริงฉันคุ้นเคยกับการใช้โหมด Hungry Man ใน Java มากขึ้น
ลักษณะของสไตล์ขี้เกียจคือการโหลดล่าช้า
ลักษณะของสไตล์ Hungry Han คือมันถูกโหลดตั้งแต่เริ่มต้นดังนั้นคุณสามารถกลับมาได้โดยตรงเมื่อคุณใช้มัน (ฉันแนะนำสิ่งนี้อีกเพราะไม่จำเป็นต้องพิจารณาปัญหาความปลอดภัยของเธรดมากเกินไปแน่นอนล็อคคู่คู่ กล่าวถึงเพื่อแก้ปัญหาการซิงโครไนซ์)
รหัสของการใช้บันทึกบันทึกด้วยสไตล์ Hungry Han มีดังนี้:
Logutil ระดับสาธารณะ {Private Static Logutilinstance = ใหม่ logutil (); () {} logUtil public Static logUtil getInstance () {return logutilInstance;} การดีบักโมฆะสาธารณะ (String msg) {ถ้า (debug> = ระดับ) {system.out.print ln (msg);}} ข้อมูลโมฆะสาธารณะ {if (info> = ระดับ) {system.out.println (msg);}} ข้อผิดพลาดโมฆะสาธารณะ (String msg) {ถ้า (ข้อผิดพลาด> = ระดับ) {system.out.println (msg); (สตริง [] ศิลปะ) {logutil.getInstance ()