مفهوم:
نمط Singleton في Java هو نمط تصميم شائع. ينقسم نمط Singleton إلى ثلاثة أنواع: Lazy Singleton ، Hungry Singleton ، و Singleton المسجل.
يحتوي وضع Singleton على الخصائص التالية:
1. يمكن أن يكون هناك مثيل واحد فقط في فصل المفرد.
2. يجب أن تنشئ فئة Singleton مثيلها الفريد.
3. يجب أن توفر فئة Singleton هذه المثيل لجميع الكائنات الأخرى.
يضمن نمط Singleton أن يكون لدى الفصل مثيلًا واحدًا فقط ، ويستند إلى مثيله ويوفر هذا الحالة للنظام بأكمله. في أنظمة الكمبيوتر ، غالبًا ما يتم تصميم كائنات برنامج التشغيل لتجمعات مؤشرات الترابط ، وذاكرة التخزين المؤقت ، وكائنات السجل ، ومربعات الحوار ، والطابعات ، وبطاقات الرسومات كفرد. هذه التطبيقات لها وظائف مدير الموارد إلى حد ما. يمكن أن يحتوي كل كمبيوتر على العديد من الطابعات ، ولكن يمكن أن يكون التخزين المؤقت للطابعة الواحدة متاحًا لتجنب وظيفتين للطباعة المخرجين إلى الطابعة في نفس الوقت. يمكن أن يكون لكل جهاز كمبيوتر العديد من منافذ الاتصالات ، ويجب أن يدير النظام مركزيًا منافذ الاتصال هذه لتجنب ميناء اتصال واحد يتم استدعاؤه في وقت واحد بواسطة طلبين. باختصار ، فإن اختيار نموذج Singleton هو تجنب الدول غير المتسقة وتجنب الصعوبة السياسية.
فيما يلي نوعان من المقدمات: كسول وجائع
1. تحميل على الفور/نمط الجائع
قبل استدعاء الطريقة ، تم إنشاء المثيل ، رمز:
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myobject {// loading now == Evil Mode private static myobject myobject = new myobject () ؛ myobject private () {} لا يتم مزامنة طريقة getInstance () // لذلك ، قد تحدث المشكلات غير الآمنة غير الآمنة على myobject ؛}} قم بإنشاء فئة مؤشر ترابط
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myThread يمتد الموضوع {Overridepublic void run () {system.out.println (myobject.getInstance (). hashcode ()) ؛}} إنشاء فئة تشغيل
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة تشغيل {public static void main (string [] args) {mythread t = new MyThread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ t.start () ؛ t.start () ؛ t.start () ؛ T.Start () ؛}} نتائج التشغيل
1 167772895
2 167772895
3 167772895
HashCode هو نفس القيمة ، مما يعني أن الكائن هو نفسه أيضًا ، مما يعني أنه يتم تنفيذ وضع التحميل الفوري.
2. الكسول التحميل/كسول
سيتم إنشاء المثيل بعد استدعاء الطريقة. يمكن أن تكون خطة التنفيذ هي وضع مثيل في المُنشئ بدون المعلمة ، بحيث يتم إنشاء مثيل للكائن فقط عندما يتم استدعاء الطريقة. شفرة:
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myobject {private static myobject myobject ؛ private myobject () {} myobject getInstance (} {// تأخير if (myobject! = null) {} {myobject قم بإنشاء فئة مؤشر ترابط
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myThread يمتد الموضوع {Overridepublic void run () {system.out.println (myobject.getInstance (). hashcode ()) ؛}} إنشاء فئة تشغيل
package com.weishiyo.learn.day8.singleton.ep2 ؛ الفئة العامة تشغيل {public static void main (string [] args) {mythread t1 = new MyThread () ؛ نتائج التشغيل
1 167772895
على الرغم من أن مثيلًا لكائن ما ، إذا كان في بيئة متعددة الخيوط ، ستحدث حالات متعددة ، وهو ليس نمطًا مفردة
قم بتشغيل فئة الاختبار
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة تشغيل {public static void main (string [] args) {mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ MyThread () ؛ T.Start () ؛ T.Start () ؛ T.Start () ؛ T.Start () ؛ T.Start () ؛ }} نتائج التشغيل
1 980258163
2 1224717057
3 1851889404
4 188820504
5 1672864109
نظرًا لوجود مشكلة ، نحتاج إلى حل المشكلة. الحل متعدد مؤشرات الترابط في الوضع البطيء ، الكود:
يمكن إضافة الحل الأول ، الأكثر شيوعًا ، المزامنة ، والمزامنة إلى مواقع مختلفة
الطريقة الأولى تغلق
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myobject {private static myobject myobject ؛ private myobject () {} متزامنة عامة متزامنة myObject getInstance () {// تأخير تحميل try {if (myobject! = null) {} { myobject = new myobject () ؛ }} catch (InterruptedException e) {e.printstacktrace () ؛} إرجاع myobject ؛}} ينتج عن مخطط التزامن المتزامن هذا غير فعال للغاية ويتم قفل الطريقة بأكملها
مخطط الاستخدام المتزامن الثاني
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myobject {private static myobject myobject ؛ private myobject () {} public static myObject getInstance () {// تأخير تحميل {synchronized (myobject.class) {if (myobject! thread.sleep () ؛ myobject = new myobject () ؛}}} catch (interruptedException e) {E.PrintStackTrace () ؛ هذه الطريقة هي أيضا كفاءة منخفضة للغاية. جميع الرموز في الطريقة مغلقة. تحتاج فقط إلى قفل رمز المفتاح. خطة الاستخدام الثالثة المتزامنة
package com.weishiyao.learn.day.singleton.ep ؛ public class myobject {private static myobject myobject ؛ private myobject () {} myobject static public static getInstance () {// تأخير تحميل try {if (myobject! = null) {} (myobject.class) {myobject = new myobject () ؛}}} catch (interruptedException e) { يبدو أن هذا هو الحل الأفضل ، لكن بعد تشغيله ، وجدت أنه في الواقع غير آمن
نتيجة:
1 1224717057
2 971173439
3 1851889404
4 1224717057
5 1672864109
لماذا؟
على الرغم من أن العبارة التي تنشئ كائنًا مغلقًا ، إلا أن مؤشر ترابط واحد فقط يمكنه إكمال الإنشاء في وقت واحد ، بعد أن يأتي الخيط الأول لإنشاء كائن الكائن ، لا يزال بإمكان مؤشر الترابط الثاني أن يستمر في إنشائه ، لأننا قفلان عبارة الإنشاء فقط ، حل المشكلة هذا
حزمة com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myobject {private static myobject myobject ؛ private myobject () {} myobject static public getInstance () {// تأخير تحميل trying {if (myobject! = null) {} (myobject.class) {if (myobject == null) {myObject = new myobject () ؛}}} catch (interruptedException e) {eprintstacktrace () ؛} إرجاع myobject ؛}} فقط أضف حكمًا آخر إلى القفل لضمان المفرد. هذه هي آلية التحقق المزدوجة DCL
النتائج كما يلي:
1 1224717057
2 1224717057
3 1224717057
4 1224717057
5 1224717057
3. استخدم فئات ثابتة مدمجة لتنفيذ حالات واحدة
الكود الرئيسي
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myobject {// طريقة الفئة الداخلية الخاصة بالفئة الثابتة الخاصة myobjectHandler {private static myobject myobject = new myobject () ؛ رمز فئة الموضوع
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myThread يمتد الموضوع {Overridepublic void run () {system.out.println (myobject.getInstance (). hashcode ()) ؛}} تشغيل الفصل
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة تشغيل {public static void main (string [] args) {mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ MyThread () ؛ T.Start () ؛ T.Start () ؛ T.Start () ؛ T.Start () ؛ T.Start () ؛ }} نتيجة
1851889404
1851889404
1851889404
1851889404
1851889404
من خلال الطبقات الثابتة الداخلية ، يتم الحصول على نمط المفرد الآمن الخيط
رابعا. تسلسل وفرط أنماط المفرد
يمكن للفئات الثابتة المدمجة تحقيق مشاكل سلامة مؤشرات الترابط ، ولكن إذا واجهت كائنات تسلسلية ، فإن النتيجة التي تم الحصول عليها باستخدام الطريقة الافتراضية لا تزال متعددة الحالات.
رمز myobject
package com.weishiyao.learn.day8.singleton.ep5 ؛ import java.io.serializable ؛ myobject الطبقة العامة الأطراف القابلة للتسلسل {/****/private static final long serialversionuid = 888l ؛ {} public static myobject getInstance () {return myobjectHandler.myObject ؛} // myobject readResolve () {// system.out.println ("تم استدعاء طريقة ReadResolve!") ؛ عمل
حزمة com.weishiyao.learn.day.singleton.ep ؛ استيراد java.io.file SaveAndread {public static void main (string [] args) {try {myObject myObject = myobject.getInstance () ؛ fileOutputTream fosref = new FileOutputStream (ملف جديد ("myobjectfile.txt")) ObjectOutputStream (fosref) ؛ oosref.writeObject (myobject) ؛ oosref.close () ؛ fosref.close () ؛ system.out.println (myobject.hashcode ()) ؛ {E.PrintStackTrace () ؛} fileInputStream fisRef ؛ Try {fisref = new FileInputStream (ملف جديد ("myobjectfile.txt")) ؛ ObjectInputStream IOSREF = جديد ObjectInputStream (fisref) ؛ myobject myobject = (myObject) iosref.ReadObject () ؛ iosref.close () ؛ fisref.close () ؛ system.out.println (myobject.hashcode ()) ؛} catch (fileNotfoundException e) {E.PrintStacktrace () ؛ {E.PrintStackTrace () ؛}}} نتيجة
1 970928725
2 1099149023
تثبت اثنين من الرموز المختلفين أنها ليست نفس الكائن. الحل ، أضف الرمز التالي
MyObject المحمي readResolve () {system.out.println ("تم استدعاء طريقة ReadResolve!") استدعاء أثناء التخلص من التسلط ، يمكنك الحصول على نفس الكائن
system.out.println (myobject.readResolve (). hashcode ()) ؛
نتيجة
1 1255301379
2 تم استدعاء طريقة ReadResolve!
3 1255301379
يثبت نفس رمز hashcode أنه يتم الحصول على نفس الكائن
5. استخدم كتل التعليمات البرمجية الثابتة لتنفيذ حالة واحدة
يتم بالفعل تنفيذ الرمز في كتلة الكود الثابت عند استخدام الفصل ، بحيث يمكن استخدام ميزة الكود الثابت لتنفيذ وضع الربح البسيط.
فئة myobject
package com.weishiyao.learn.day.singleton.ep ؛ public class myobject {private static myobject مثيل = null ؛ private myobject () {super () ؛} ثابت {مثيل = جديد myobject () ؛ فئة الموضوع
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myThread يمتد الموضوع {Overridepublic void run () {for (int i = ؛ i <؛ i ++) تشغيل الفصل
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة تشغيل {public static void main (string [] args) {mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ MyThread () ؛ 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. استخدم أنواع بيانات التعداد لتنفيذ وضع Singleton
تتشابه خصائص تعداد التعداد وكتل الرمز الثابت. عند استخدام التعدادات ، سيتم استدعاء المنشئ تلقائيًا ويمكن أيضًا استخدامه لتنفيذ وضع Singleton.
فئة myobject
package com.weishiyao.learn.day.singleton.ep ؛ استيراد java.sql.connection ؛ استيراد java.sql.drivermanager ؛ استيراد java.sql.sqlexception ؛ تعداد عام myobject {connectionFactory ؛ url = "jdbc: mysql: // ...:/weChat_؟ useUnicode = true & farmenChoding = utf-" ؛ string name = "root" ؛ string password = "؛ (classnotfoundException e) {E.PrintStackTrace () ؛} catch (sqlexception e) {E.PrintStackTrace () ؛}} connection getConnection () {return connection ؛}} فئة الموضوع
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myThread يمتد الموضوع {Overridepublic void run () {for (int i = ؛ i <؛ i ++) تشغيل الفصل
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة تشغيل {public static void main (string [] args) {mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ mythread t = new mythread () ؛ MyThread () ؛ 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 {system.out.println ("تم استدعاء بناء myobject") ؛ url url = "jdbc: mysql: // ...:/wechat_؟ useUnicode = true & pariceencoding = utf-" drivermanager.getConnection (url ، الاسم ، كلمة المرور) ؛} catch (classnotfoundException e) {E.PrintStackTrace () ؛ myenumsingleton.connectionfactory.getConnection () ؛}} تغيير رمز الموضوع
package com.weishiyao.learn.day.singleton.ep ؛ الطبقة العامة myThread يمتد الموضوع {Overridepublic void run () {for (int i = ؛ i <؛ i ++) نتيجة
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
يلخص ما ورد أعلاه المواقف والحلول المختلفة التي تمت مواجهتها عند الجمع بين وضع المصلحة الواحدة مع متعدد الخيوط ، بحيث يمكن مراجعتها عند استخدامها لاحقًا.