แนวคิด:
รูปแบบ Singleton ใน Java เป็นรูปแบบการออกแบบทั่วไป รูปแบบ Singleton แบ่งออกเป็นสามประเภท: Lazy Singleton, Hungry Singleton และ Singleton ที่ลงทะเบียน
โหมด Singleton มีลักษณะดังต่อไปนี้:
1. มีเพียงอินสแตนซ์เดียวในคลาสซิงเกิลตัน
2. คลาส Singleton ต้องสร้างอินสแตนซ์ที่เป็นเอกลักษณ์ของตัวเอง
3. คลาส Singleton ต้องจัดเตรียมอินสแตนซ์นี้ให้กับวัตถุอื่น ๆ ทั้งหมด
รูปแบบ Singleton ช่วยให้มั่นใจได้ว่าคลาสมีเพียงหนึ่งอินสแตนซ์และสร้างมันเองและให้อินสแตนซ์นี้กับระบบทั้งหมด ในระบบคอมพิวเตอร์วัตถุไดรเวอร์สำหรับพูลเธรดแคชวัตถุบันทึกกล่องโต้ตอบเครื่องพิมพ์และการ์ดกราฟิกมักถูกออกแบบมาเป็นซิงเกิล แอปพลิเคชันเหล่านี้มีฟังก์ชั่นการทำงานของตัวจัดการทรัพยากรมากหรือน้อย คอมพิวเตอร์แต่ละเครื่องสามารถมีเครื่องพิมพ์หลายเครื่อง แต่เครื่องพิมพ์เครื่องพิมพ์เพียงเครื่องเดียวเท่านั้นที่สามารถใช้งานได้เพื่อหลีกเลี่ยงงานพิมพ์สองงานที่ถูกส่งออกไปยังเครื่องพิมพ์ในเวลาเดียวกัน คอมพิวเตอร์แต่ละเครื่องสามารถมีพอร์ตการสื่อสารได้หลายพอร์ตและระบบควรจัดการพอร์ตการสื่อสารเหล่านี้จากส่วนกลางเพื่อหลีกเลี่ยงพอร์ตการสื่อสารหนึ่งที่ถูกเรียกพร้อมกันโดยสองคำขอ ในระยะสั้นการเลือกแบบจำลองซิงเกิลคือการหลีกเลี่ยงรัฐที่ไม่สอดคล้องกันและหลีกเลี่ยงความเป็นทางการเมือง
นี่คือการแนะนำสองประเภท: ขี้เกียจและหิว
1. โหลดทันที/สไตล์หิว
ก่อนที่จะเรียกวิธีการอินสแตนซ์ได้ถูกสร้างรหัส:
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {// โหลดตอนนี้ == ความชั่วร้ายโหมดส่วนตัวคงที่ myobject myobject = new myobject (); myobject ส่วนตัว () {} public Static myobject getinstance () วิธี getInstance () ไม่ได้ซิงโครไนซ์ // ดังนั้นปัญหาที่ไม่ปลอดภัยที่ไม่ปลอดภัยอาจเกิดขึ้น return myObject;}} สร้างคลาสเธรด
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ Mythread ขยายเธรด {@Overridepublic เป็นโมฆะ Run () {system.out.println (myObject.getInstance (). hashCode ());}}}} สร้างคลาสรัน
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะรัน {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {Mythread t = ใหม่ mythread (); Mythread t = new Mythread (); mythread t = new mythread (); t.start (); t.start (); t.start ();}} การรันผลลัพธ์
1 167772895
2 167772895
3 167772895
HashCode เป็นค่าเดียวกันซึ่งหมายความว่าวัตถุนั้นเหมือนกันซึ่งหมายความว่ามีการใช้โหมดการโหลดทันที
2. ขี้เกียจโหลด/ขี้เกียจ
อินสแตนซ์จะถูกสร้างขึ้นหลังจากวิธีการที่เรียกว่า แผนการดำเนินการสามารถนำการสร้างอินสแตนซ์ลงในตัวสร้างพารามิเตอร์ที่ไม่มีพารามิเตอร์เพื่อให้อินสแตนซ์ของวัตถุจะถูกสร้างขึ้นเมื่อมีการเรียกวิธีการเท่านั้น รหัส:
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {ส่วนตัว myobject myobject ส่วนตัว myobject ส่วนตัว () {} สาธารณะคงที่ myobject getinstance () {// การโหลดล่าช้าถ้า (myobject! = null) {} {myobject สร้างคลาสเธรด
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ Mythread ขยายเธรด {@Overridepublic เป็นโมฆะ Run () {system.out.println (myObject.getInstance (). hashCode ());}}}} สร้างคลาสรัน
แพ็คเกจ com.weishiyao.learn.day8.singleton.ep2; การเรียกใช้ระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {Mythread t1 = ใหม่ mythread (); t1.start ();}}}}} การรันผลลัพธ์
1 167772895
แม้ว่าอินสแตนซ์ของวัตถุจะถูกนำไปใช้ถ้ามันอยู่ในสภาพแวดล้อมแบบมัลติเธรด แต่หลายกรณีจะเกิดขึ้นซึ่งไม่ใช่รูปแบบซิงเกิล
เรียกใช้คลาสทดสอบ
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะรัน {โมฆะคงที่สาธารณะ (สตริง [] args) {Mythread t = ใหม่ mythread (); mythread t = new mythread (); mythread t = new mythread (); Mythread (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); - การรันผลลัพธ์
1 980258163
2 1224717057
3 1851889404
4 188820504
5 1672864109
เนื่องจากมีปัญหาเราจึงต้องแก้ปัญหา โซลูชันแบบมัลติเธรดในโหมดขี้เกียจรหัส:
ทางออกแรกโดยทั่วไปส่วนใหญ่เพิ่มการซิงโครไนซ์และซิงโครไนซ์สามารถเพิ่มไปยังตำแหน่งที่แตกต่างกัน
วิธีแรกล็อค
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {ส่วนตัว myobject myobject ส่วนตัว; ส่วนตัว myobject () {} ซิงโครไนซ์สาธารณะ myobject getinstance () {// หน่วงโหลดลอง {ถ้า (myobject! = null myObject = new myObject (); }} catch (interruptedException e) {e.printStackTrace ();} return myObject;}} รูปแบบการซิงโครไนซ์แบบซิงโครไนซ์นี้ส่งผลให้ไม่มีประสิทธิภาพและวิธีการทั้งหมดถูกล็อค
รูปแบบการใช้งานที่ซิงโครไนซ์ครั้งที่สอง
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {ส่วนตัว myobject myobject ส่วนตัว myobject ส่วนตัว () {} สาธารณะคงที่ myobject getinstance () {// การโหลดล่าช้า {synchronized thread.sleep (); myObject = new myObject ();}}} catch (interruptedException e) {e.printStackTrace ();} return myObject;}} วิธีนี้ยังมีประสิทธิภาพต่ำมาก รหัสทั้งหมดในวิธีการถูกล็อค คุณจะต้องล็อครหัสคีย์เท่านั้น แผนการใช้งานที่ประสานกันครั้งที่สาม
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {ส่วนตัว myobject myobject ส่วนตัว; ส่วนตัว myobject () {} สาธารณะคงที่ myobject getinstance () {// หน่วงเวลาลอง {ถ้า (myobject! = null) {} (myObject.class) {myObject = new myObject ();}}} catch (interruptedException e) {e.printStackTrace ();} return myObject;}}} นี่ดูเหมือนจะเป็นทางออกที่ดีที่สุด แต่หลังจากเรียกใช้แล้วฉันพบว่าจริง ๆ แล้วมันไม่ปลอดภัยที่ไม่ปลอดภัย
ผลลัพธ์:
1 1224717057
2 971173439
3 1851889404
4 1224717057
5 1672864109
ทำไม
แม้ว่าคำสั่งที่สร้างวัตถุจะถูกล็อค แต่มีเพียงหนึ่งเธรดเดียวเท่านั้นที่สามารถสร้างการสร้างได้ในแต่ละครั้งหลังจากเธรดแรกเข้ามาเพื่อสร้างวัตถุวัตถุเธรดที่สองยังคงสามารถสร้างได้ต่อไปเพราะเราล็อคคำสั่งการสร้างเท่านั้น
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {ส่วนตัว myobject myobject ส่วนตัว; ส่วนตัว myobject () {} สาธารณะคงที่ myobject getinstance () {// การโหลดล่าช้าลอง {ถ้า (myobject! = null) {} (myObject.class) {if (myObject == null) {myObject = new myObject ();}}}} catch (interruptedException e) {E.printStackTrace ();} return myObject;}}}}}} เพียงเพิ่มการตัดสินอีกครั้งในล็อคเพื่อให้แน่ใจว่ามีซิงเกิลตัน นี่คือกลไกการตรวจสอบ DCL สองครั้ง
ผลลัพธ์มีดังนี้:
1 1224717057
2 1224717057
3 1224717057
4 1224717057
5 1224717057
3. ใช้คลาสคงที่ในตัวเพื่อใช้เคสเดียว
รหัสหลัก
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {// วิธีชั้นเรียนชั้นเรียนชั้นเรียนส่วนตัวคลาสคงที่ myobjecthandler {ส่วนตัว myobject myobject = new myobject ();} public myobject () รหัสคลาสเธรด
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ Mythread ขยายเธรด {@Overridepublic เป็นโมฆะ Run () {system.out.println (myObject.getInstance (). hashCode ());}}}} วิ่งชั้นเรียน
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะรัน {โมฆะคงที่สาธารณะ (สตริง [] args) {Mythread t = ใหม่ mythread (); mythread t = new mythread (); mythread t = new mythread (); Mythread (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); - ผลลัพธ์
1851889404
1851889404
1851889404
1851889404
1851889404
ผ่านคลาสคงที่ภายในจะได้รับรูปแบบ Singleton ที่ปลอดภัยจากด้าย
iv. ทำให้เป็นลำดับและ deserialize รูปแบบซิงเกิล
คลาสคงที่ในตัวสามารถบรรลุปัญหาด้านความปลอดภัยของเธรด แต่ถ้าคุณพบวัตถุที่เป็นอนุกรมผลลัพธ์ที่ได้จากวิธีการเริ่มต้นยังคงเป็นหลายกรณี
รหัส myObject
แพ็คเกจ com.weishiyao.learn.day8.singleton.ep5; นำเข้า java.io.serializable; MyObject ระดับสาธารณะใช้ serializable {/****/ส่วนตัวคงที่สุดท้าย long serialversionuid = 888l; // วิธีชั้นเรียน {} สาธารณะคงที่ myObject getInstance () {return myobjecthandler.myobject;} // ป้องกัน myobject readresolve () {// system.out.println ("วิธี readresolve ถูกเรียก!"); // กลับ myobjecthandler.myobject; //} ธุรกิจ
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; นำเข้า java.io.file; นำเข้า java.io.fileinputstream; นำเข้า java.io.filenotfoundException; นำเข้า Java.io.fileOutputStream; นำเข้า Java.io.ioException; SaveandRead {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ลอง {myObject myObject = myObject.getInstance (); fileOutputStream fosref = new FileOutputStream (ไฟล์ใหม่ ("myObjectFile.txt"))); ObjectOutputStream (fosref); oosref.writeObject (myobject); oosref.close (); fosref.close (); system.out.println (myobject.hashcode ()); {E.printStackTrace ();} fileInputStream fisref; ลอง {fisref = ใหม่ fileInputStream (ไฟล์ใหม่ ("myObjectFile.txt")); ObjectInputStream iOSREF = New ObjectInputStream (FISREF); iosref.readObject (); iosref.close (); fisref.close (); system.out.println (myobject.hashcode ());} catch (filenotfoundexception e) {e.printstacktrace (); {E.PrintStackTrace ();}}} ผลลัพธ์
1 970928725
2 1099149023
hashcodes สองตัวที่แตกต่างกันพิสูจน์ว่าพวกเขาไม่ใช่วัตถุเดียวกัน วิธีแก้ปัญหาเพิ่มรหัสต่อไปนี้
ได้รับการปกป้อง myObject readResOlve () {system.out.println ("วิธีการ readResolve ถูกเรียกว่า!"); return myobjecthandler.myobject;} เรียกว่าในระหว่าง deserialization คุณสามารถรับวัตถุเดียวกันได้
System.out.println (myobject.readresolve (). hashcode ());
ผลลัพธ์
1 1255301379
2 วิธีการ readresolve ถูกเรียก!
3 1255301379
HashCode เดียวกันพิสูจน์ว่าได้รับวัตถุเดียวกัน
5. ใช้บล็อกรหัสแบบคงที่เพื่อใช้เคสเดียว
รหัสในบล็อกรหัสคงที่ถูกดำเนินการแล้วเมื่อใช้คลาสดังนั้นคุณสมบัติของรหัสสแตติกอย่างรวดเร็วสามารถใช้เพื่อใช้โหมดกำไรอย่างง่าย
คลาส MyObject
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ myobject {อินสแตนซ์ myobject แบบคงที่ส่วนตัว = null; ส่วนตัว myobject () {super ();} คงที่ {อินสแตนซ์ = new myObject ();} สาธารณะ ชั้นเรียนด้าย
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ Mythread ขยายเธรด {@Overridepublic เป็นโมฆะ Run () {สำหรับ (int i =; i <; i ++) {system.out.println (myobject.getInstance (). hashcode () วิ่งชั้นเรียน
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะรัน {โมฆะคงที่สาธารณะ (สตริง [] args) {Mythread t = ใหม่ mythread (); mythread t = new mythread (); mythread t = new mythread (); Mythread (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); - ผลการทำงาน:
1 1678885403
2 1678885403
3 1678885403
4 1678885403
5 1678885403
6 1678885403
7 1678885403
8 1678885403
9 1678885403
10 1678885403
11 1678885403
12 1678885403
13 1678885403
14 1678885403
15 1678885403
16 1678885403
17 1678885403
18 1678885403
19 1678885403
20 1678885403
21 1678885403
22 1678885403
23 1678885403
24 1678885403
25 1678885403
รูปแบบ Singleton ที่ปลอดภัยจากเธรดได้รับความสำเร็จผ่านคุณสมบัติของการเรียกใช้บล็อกรหัสแบบคงที่เพียงครั้งเดียวเท่านั้น
6. ใช้ประเภทข้อมูล enum enum เพื่อใช้โหมด Singleton
ลักษณะของ enum enum และบล็อกรหัสคงที่มีความคล้ายคลึงกัน เมื่อใช้ enums คอนสตรัคเตอร์จะถูกเรียกโดยอัตโนมัติและยังสามารถใช้ในการใช้โหมดซิงเกิล
คลาส MyObject
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; นำเข้า java.sql.connection; นำเข้า java.sql.driverManager นำเข้า java.sql.sqlexception; enum myobject public "jdbc: mysql: // ... :/wechat_? useunicode = true & characterencoding = utf-"; string name = "root"; string password = "" String drivername = "com.mysql.jdbc.driver" class.forname {E.PrintStackTrace ();} catch (sqlexception e) {e.printstacktrace ();}} การเชื่อมต่อสาธารณะ getConnection () {return connection;}} ชั้นเรียนด้าย
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะ Mythread ขยายเธรด {@Overridepublic void run () {สำหรับ (int i =; i <; i ++) {system.out.println (myobject.connectionFactory.getConnection () วิ่งชั้นเรียน
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะรัน {โมฆะคงที่สาธารณะ (สตริง [] args) {Mythread t = ใหม่ mythread (); mythread t = new mythread (); mythread t = ใหม่ mythread (); mythread t = mythread ใหม่ Mythread (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); T.Start (); - การรันผลลัพธ์
1 โครงสร้าง myObject ถูกเรียก
2 56823666
3 56823666
4 56823666
5 56823666
6 56823666
7 56823666
8 56823666
9 56823666
10 56823666
11 56823666
12 56823666
13 56823666
14 56823666
15 56823666
16 56823666
17 56823666
18 56823666
19 56823666
20 56823666
21 56823666
22 56823666
23 56823666
24 56823666
25 56823666
26 56823666
วิธีการเขียนข้างต้นเปิดเผยคลาสการแจงนับซึ่งละเมิด "หลักการความรับผิดชอบเดี่ยว" คุณสามารถใช้คลาสเพื่อห่อหุ้มการแจงนับ
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; นำเข้า java.sql.connection; นำเข้า java.sql.drivermanager; นำเข้า java.sql.sqlexception; ชั้นเรียนสาธารณะ myobject ของ myObject ถูกเรียกว่า "); string url =" jdbc: mysql: // ... :/wechat_? useunicode = true & characterencoding = utf- "; string name =" root "; string password =" "String drivername =" com.mysql.jdbc.driver รหัสผ่าน);} catch (classnotfoundexception e) {e.printstacktrace ();} catch (sqlexception e) {e.printstacktrace ();}} การเชื่อมต่อสาธารณะ getConnection () {return connection;}} การเชื่อมต่อแบบคงที่สาธารณะ เปลี่ยนรหัสเธรด
แพ็คเกจ com.weishiyao.learn.day.singleton.ep; คลาสสาธารณะชั้นเรียน Mythread ขยายเธรด {@Overridepublic เป็นโมฆะ Run () {สำหรับ (int i =; i <; i ++) {system.out.println (myobject.getConnection (). hashcode (); ผลลัพธ์
1 โครงสร้าง myObject ถูกเรียก
2 1948356121
3 1948356121
4 1948356121
5 1948356121
6 1948356121
7 1948356121
8 1948356121
9 1948356121
10 1948356121
11 1948356121
12 1948356121
13 1948356121
14 1948356121
15 1948356121
16 1948356121
17 1948356121
18 1948356121
19 1948356121
20 1948356121
21 1948356121
22 1948356121
23 1948356121
24 1948356121
25 1948356121
26 1948356121
ข้างต้นสรุปสถานการณ์และโซลูชันที่พบเมื่อรวมโหมดดอกเบี้ยเดี่ยวเข้ากับมัลติเธรดเพื่อให้สามารถตรวจสอบได้เมื่อใช้ในภายหลัง