Window.pipedriveLeadboosterConfig = { القاعدة: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', الإصدار: 2, } ؛(الدالة () { var w = نافذة إذا كان (w.LeadBooster) { console.warn('LeadBooster موجود بالفعل') } وإلا { { w.LeadBooster = { q: [], على: دالة (ن، ح) { { هذا.q.push({ t: 'o'، n: n، n: n، h: h }) }, الزناد: الدالة (n) { هذا.q.push({ t: 't'، n: n: n }) }, } } })() التزامن في جافا الجزء 1 - مقدمة - The Codest
The Codest
  • نبذة عنا
  • الخدمات
    • تطوير البرمجيات
      • تطوير الواجهة الأمامية
      • تطوير الواجهة الخلفية
    • Staff Augmentation
      • مطورو الواجهة الأمامية
      • مطورو الواجهة الخلفية
      • مهندسو البيانات
      • مهندسو السحابة
      • مهندسو ضمان الجودة
      • أخرى
    • استشاري
      • التدقيق والاستشارات
  • الصناعات
    • التكنولوجيا المالية والمصرفية
    • E-commerce
    • أدتك
    • التكنولوجيا الصحية
    • التصنيع
    • الخدمات اللوجستية
    • السيارات
    • إنترنت الأشياء
  • القيمة مقابل
    • CEO
    • CTO
    • مدير التوصيل
  • فريقنا
  • دراسات الحالة
  • اعرف كيف
    • المدونة
    • اللقاءات
    • ندوات عبر الإنترنت
    • الموارد
الوظائف تواصل معنا
  • نبذة عنا
  • الخدمات
    • تطوير البرمجيات
      • تطوير الواجهة الأمامية
      • تطوير الواجهة الخلفية
    • Staff Augmentation
      • مطورو الواجهة الأمامية
      • مطورو الواجهة الخلفية
      • مهندسو البيانات
      • مهندسو السحابة
      • مهندسو ضمان الجودة
      • أخرى
    • استشاري
      • التدقيق والاستشارات
  • القيمة مقابل
    • CEO
    • CTO
    • مدير التوصيل
  • فريقنا
  • دراسات الحالة
  • اعرف كيف
    • المدونة
    • اللقاءات
    • ندوات عبر الإنترنت
    • الموارد
الوظائف تواصل معنا
السهم الخلفي العودة إلى الوراء
2022-06-15
تطوير البرمجيات

التزامن في جافا الجزء 1 - مقدمة

The Codest

رافال ساويكي

مطور جافا

اقرأ الجزء الأول من سلسلة مدونتنا المخصصة للتزامن في Java. في المقالة التالية سوف نلقي نظرة فاحصة على الاختلافات بين مؤشرات الترابط والعمليات، وتجمعات مؤشرات الترابط، والمنفذين وغيرها الكثير!

بشكل عام، يكون نهج البرمجة التقليدي متسلسلًا. كل شيء في البرنامج يحدث خطوة بخطوة في كل مرة.
ولكن، في الواقع، فإن التوازي هو الطريقة التي يعمل بها العالم بأسره - إنها القدرة على تنفيذ أكثر من مهمة في وقت واحد.

الخيط مقابل العملية

لمناقشة مواضيع متقدمة مثل التزامن في جافا أو تعدد مؤشرات الترابط، علينا أن نتفق على بعض التعريفات المشتركة لنتأكد من أننا على نفس الصفحة.

لنبدأ بالأساسيات. في العالم غير المتسلسل، لدينا نوعان من ممثلي التزامن: العمليات و
الخيوط. العملية هي مثيل للبرنامج قيد التشغيل. وعادةً ما تكون معزولة عن العمليات الأخرى.
نظام التشغيل مسؤول عن تخصيص الموارد لكل عملية. وعلاوة على ذلك، فإنه يعمل كموصل
الجداول الزمنية والتحكم فيها.

الخيط هو نوع من العمليات ولكن على مستوى أقل، ولذلك يُعرف أيضًا باسم الخيط الخفيف. يمكن تشغيل عدة خيوط في عملية واحدة
عملية. هنا يعمل البرنامج كجدول زمني ومراقب للخيوط. بهذه الطريقة تظهر البرامج الفردية
مهام متعددة في نفس الوقت.

الفرق الأساسي بين الخيوط والعمليات هو مستوى العزل. العملية لديها مجموعة خاصة بها من
الموارد، بينما يشارك مؤشر الترابط البيانات مع مؤشرات ترابط أخرى. قد يبدو أنه نهج معرض للخطأ وهو كذلك بالفعل. بالنسبة لـ
الآن، دعنا لا نركز على ذلك لأنه خارج نطاق هذا المقال.

العمليات، الخيوط - حسناً... ولكن ما هو التزامن بالضبط؟ التزامن يعني أنه يمكنك تنفيذ مهام متعددة في نفس الوقت
الوقت. لا يعني ذلك أن هذه المهام يجب أن تعمل في وقت واحد - وهذا هو معنى التوازي. كونكورينيك في جافاي أيضًا لا
تتطلب أن يكون لديك وحدات معالجة مركزية متعددة أو حتى أنوية متعددة. يمكن تحقيق ذلك في بيئة أحادية النواة من خلال الاستفادة من
تبديل السياق.

من المصطلحات المرتبطة بالتزامن هو تعدد مؤشرات الترابط. هذه ميزة للبرامج تسمح لها بتنفيذ عدة مهام في وقت واحد. لا تستخدم كل البرامج هذا النهج ولكن البرامج التي تستخدمه يمكن تسميتها متعددة الخيوط.

نحن جاهزون تقريبًا للبدء، فقط تعريف آخر. عدم التزامن يعني أن البرنامج ينفذ عمليات غير متوقفة.
فهو يبدأ مهمة ما ثم يمضي قدماً في أشياء أخرى أثناء انتظار الاستجابة. وعندما يحصل على الاستجابة، يمكنه التفاعل معها.

كل ذلك الجاز

بشكل افتراضي، كل تطبيق جافا يعمل في عملية واحدة. في هذه العملية، يوجد مؤشر ترابط واحد مرتبط بـ الرئيسي() طريقة
تطبيق. ومع ذلك، كما ذكرنا، من الممكن الاستفادة من آليات الخيوط المتعددة ضمن
البرنامج.

قابل للتشغيل

الخيط هو جافا الذي يحدث فيه السحر. هذا هو تمثيل الكائن للخيط المذكور سابقًا. إلى
إنشاء مؤشر ترابط خاص بك، يمكنك تمديد الخيط الفصل. ومع ذلك، فإنه ليس نهجاً موصى به. الخيوط يجب استخدامها كآلية لتشغيل المهمة. المهام هي أجزاء من الكود التي نريد تشغيلها في وضع متزامن. يمكننا تعريفها باستخدام قابل للتشغيل الواجهة.

لكن كفى نظريات، دعونا نضع شفرتنا في مكانها الصحيح.

المشكلة

افترض أن لدينا مصفوفتين من الأعداد. لكل مصفوفة، نريد معرفة مجموع الأعداد في مصفوفة. لنفترض أن
تظاهر بوجود الكثير من هذه المصفوفات وكل منها كبير نسبيًا. في مثل هذه الظروف، نريد الاستفادة من التزامن وجمع كل مصفوفة كمهمة منفصلة.

int[] a1 = {1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10};
int[] a2 = {10، 10، 10، 10، 10، 10، 10، 10، 10، 10، 10};
int[] a3 = {3، 4، 4، 3، 3، 4، 3، 4، 4، 2، 1، 3، 3، 7};

المهمة القابلة للتشغيل1 = () -> { {
    int sum = Arrays.stream(a1).sum();
    System.out.println("1. المجموع هو: " + المجموع);
};

المهمة القابلة للتشغيل2 = () -> { {
    int sum = Arrays.stream(a2).sum();
    System.out.println("2. المجموع هو: " + المجموع);
};

المهمة القابلة للتشغيل3 = () -> { {
    int sum = Arrays.stream(a3).sum();
    System.out.println("3. المجموع هو: " + المجموع);
};

مؤشر ترابط جديد(task1).start();
مؤشر ترابط جديد(task2).start()؛
مؤشر ترابط جديد(task3).start()؛ مؤشر ترابط جديد(task3).start();

كما ترى من الكود أعلاه قابل للتشغيل واجهة وظيفية. تحتوي على طريقة تجريدية واحدة تشغيل()
بدون حجج. إن قابل للتشغيل يجب أن تُنفذ الواجهة من قبل أي صنف يُفترض أن تكون مثيلاته
أعدم بواسطة خيط.

بمجرد تحديد مهمة يمكنك إنشاء مؤشر ترابط لتشغيلها. يمكن تحقيق ذلك عبر مؤشر ترابط جديد() المُنشئ الذي
يأخذ قابل للتشغيل كحجة لها.

الخطوة الأخيرة هي بدء() مؤشر ترابط تم إنشاؤه حديثًا. يوجد في واجهة برمجة التطبيقات أيضًا تشغيل() الطرق في قابل للتشغيل وفي
الخيط. ومع ذلك، هذه ليست طريقة للاستفادة من التزامن في Java. يؤدي الاستدعاء المباشر لكل من هذه الطرق إلى
تنفيذ المهمة في نفس مؤشر ترابط الرئيسي() طريقة التشغيل.

مجمعات الخيوط والمنفذون

عندما يكون هناك الكثير من المهام، فإن إنشاء مؤشر ترابط منفصل لكل منها ليس فكرة جيدة. إنشاء مؤشر ترابط الخيط هو
عملية ثقيلة الوزن ومن الأفضل بكثير إعادة استخدام الخيوط الموجودة بدلاً من إنشاء خيوط جديدة.

عندما يقوم برنامج ما بإنشاء العديد من سلاسل الرسائل قصيرة الأجل، فمن الأفضل استخدام تجمع سلاسل رسائل. يحتوي تجمع مؤشرات الترابط على عدد من
خيوط جاهزة للتشغيل ولكنها غير نشطة حاليًا. إعطاء قابل للتشغيل إلى التجمع يتسبب في قيام أحد الخيوط باستدعاء
تشغيل() طريقة المعطى قابل للتشغيل. بعد إكمال المهمة يظل مؤشر الترابط موجودًا وفي حالة خمول.

حسنًا، لقد فهمت - تفضل تجمع الخيوط بدلاً من الإنشاء اليدوي. ولكن كيف يمكنك الاستفادة من تجمعات الخيوط؟ إن المنفذون
على عدد من طرائق المصنع الثابتة لإنشاء تجمعات مؤشرات الترابط. على سبيل المثال newCachedThredPool() ينشئ
تجمع يتم فيه إنشاء خيوط جديدة حسب الحاجة ويتم الاحتفاظ بالخيوط الخاملة لمدة 60 ثانية. في المقابل,
newFixedThreadPool() يحتوي على مجموعة ثابتة من الخيوط، حيث يتم الاحتفاظ بالخيوط الخاملة إلى أجل غير مسمى.

دعونا نرى كيف يمكن أن تعمل في مثالنا. الآن لا نحتاج إلى إنشاء سلاسل رسائل يدويًا. بدلًا من ذلك، علينا إنشاء
خدمة المنفذ والتي توفر مجموعة من الخيوط. ثم يمكننا تعيين المهام إليها. الخطوة الأخيرة هي إغلاق الخيط
لتجنب تسرب الذاكرة. تبقى بقية الشيفرة السابقة كما هي.

ExecutorSecutorService execor = Executors.newCachedThreadPool();

المنفذ.submit(task1);
execor.submit(task2)؛
execor.submit(task3);

إيقاف التشغيل();

قابل للاستدعاء

قابل للتشغيل تبدو طريقة أنيقة لإنشاء مهام متزامنة ولكنها تعاني من عيب رئيسي واحد. لا يمكنها إرجاع أي
القيمة. علاوة على ذلك، لا يمكننا تحديد ما إذا كانت المهمة قد اكتملت أم لا. كما أننا لا نعرف ما إذا كانت قد اكتملت أم لا
بشكل طبيعي أو استثنائي. والحل لهذه العلل هو قابل للاستدعاء.

قابل للاستدعاء مشابه ل قابل للتشغيل بطريقة ما يلتف أيضًا على المهام غير المتزامنة. الفرق الرئيسي هو أنها قادرة على
إرجاع قيمة. يمكن أن تكون القيمة المُرجَعة من أي نوع (غير بدائي) مثل قابل للاستدعاء الواجهة عبارة عن نوع معلمات.
قابل للاستدعاء هي واجهة وظيفية تحتوي على استدعاء() التي يمكن أن ترمي طريقة الاستثناء.

والآن لنرى كيف يمكننا الاستفادة من قابل للاستدعاء في مشكلتنا المصفوفة.

int[] a1 = {1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10};
int[] a2 = {10، 10، 10، 10، 10، 10، 10، 10، 10، 10، 10};
int[] a3 = {3، 4، 4، 3، 3، 4، 3، 4، 4، 2، 1، 3، 3، 7};

Callable task1 = () -> Arrays.stream(a1).sum();
Callable task2 = () = () -> Arrays.stream(a2).sum()؛
Callable task3 = () -> Arrays.stream(a3).sum()؛

ExecutorSecutorService execor = Executors.newCachedThreadPool();
Future Future1 = execor.submit(task1);
المستقبل المستقبل2 = executor.submit(task2);
Future Future3 = executor.submit(task3)؛ والمستقبلالمستقبل3 = executor.submit(task3);

System.out.println("1. المجموع هو: " + future1.get());
System.out.println("2. المجموع هو: " + future2.get())؛
System.out.println("3. المجموع هو: " + future3.get())؛ System.out.println("3. المجموع هو: " + future3.get());

المنفذ.إيقاف التشغيل();

حسناً، يمكننا أن نرى كيف قابل للاستدعاء ثم يتم إنشاؤه ثم إرساله إلى خدمة المنفذ. ولكن ما هو المستقبل?
المستقبل يعمل كجسر بين الخيوط. يتم إنتاج مجموع كل مصفوفة في خيط منفصل ونحتاج إلى طريقة لـ
الحصول على هذه النتائج إلى الرئيسي().

لاسترداد النتيجة من المستقبل نحتاج إلى الاتصال ب الحصول على () الطريقة. هنا يمكن أن يحدث أحد أمرين. أولاً، يمكن أن يحدث
نتيجة العملية الحسابية التي أجراها قابل للاستدعاء متاحة. ثم نحصل عليها على الفور. ثانيًا، النتيجة ليست
جاهز بعد. في هذه الحالة الحصول على () حتى تصبح النتيجة متاحة.

كومبيوتابل فيوتشر

المشكلة في المستقبل هو أنه يعمل في "نموذج الدفع". عند استخدام المستقبل عليك أن تكون مثل الرئيس الذي
يسأل باستمرار: "هل أنجزت مهمتك؟ هل هي جاهزة؟" حتى تقدم نتيجة. العمل تحت ضغط مستمر هو
باهظة الثمن. أفضل طريقة أفضل بكثير هي أن تطلب المستقبل ما يجب القيام به عندما يكون جاهزًا لمهمته. لسوء الحظ
المستقبل لا يمكن أن تفعل ذلك ولكن كومبيوتابل فيوتشر يمكن.

كومبيوتابل فيوتشر يعمل في "نموذج السحب". يمكننا إخبارها بما يجب أن تفعله بالنتيجة عندما تكمل مهامها. إنه
هو مثال على النهج غير المتزامن.

كومبيوتابل فيوتشر يعمل بشكل مثالي مع قابل للتشغيل ولكن ليس مع قابل للاستدعاء. بدلاً من ذلك، من الممكن توفير مهمة إلى
كومبيوتابل فيوتشر في شكل المورد.

لنرى كيف يرتبط ما سبق بمشكلتنا.

int[] a1 = {1, 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 10};
int[] a2 = {10، 10، 10، 10، 10، 10، 10، 10، 10، 10، 10};
int[] a3 = {3، 4، 4، 3، 3، 4، 3، 4، 4، 2، 1، 3، 3، 7};

CompletableFuture.supplyAsync(() -> Arrays.stream(a1).sum())
                .thenAccept(System.out::println);

CompletableFuture.supplyAsync(() -> Arrays.stream(a2).sum()))
                .thenAccept(System.out::println);

CompletableFuture.supplyAsync(() -> Arrays.stream(a3).sum()))
                .thenAccept(System.out::println);

أول ما يلفت انتباهك هو مدى قصر هذا الحل. إلى جانب ذلك، يبدو أيضاً أنيقاً ومرتباً.

المهمة إلى اكتمالالمستقبل يمكن توفيرها بواسطة توريد مزامنة() التي تأخذ المورد أو بواسطة تشغيل مزامنة() أن
يأخذ قابل للتشغيل. يتم تعريف رد النداء - وهو جزء من التعليمات البرمجية التي يجب تشغيلها عند اكتمال المهمة - بواسطة ثم قبول()
الطريقة.

الاستنتاجات

جافا يوفر الكثير من الأساليب المختلفة للتزامن. في هذه المقالة، بالكاد تطرقنا إلى هذا الموضوع.

ومع ذلك، فقد غطينا أساسيات الخيط, قابل للتشغيل, قابل للاستدعاءو قابل للاستدعاء في المستقبل وهو ما يطرح نقطة جيدة
لمزيد من التحقيق في الموضوع.

مقالات ذات صلة

تطوير البرمجيات

9 أخطاء يجب تجنبها أثناء البرمجة بلغة جافا

ما الأخطاء التي يجب تجنبها أثناء البرمجة بلغة جافا؟ في المقالة التالية نجيب على هذا السؤال.

The Codest
رافال ساويكي مطور جافا
الحلول المؤسسية وحلول التوسعة

الطريقة الصحيحة للعثور على أفضل مطوري جافا

قد يكون العثور على مطور جافا المثالي مهمة شاقة. فمع نمو الطلب في السوق على هؤلاء المهنيين بوتيرة مذهلة، قد تبدو المصادر المتاحة للبحث عن المواهب في بعض الأحيان...

The Codest
غريغورز روزموس قائد وحدة جافا
الحلول المؤسسية وحلول التوسعة

10 شركات في دبي تستحق المشاهدة في 2020

دبي هي قلب الإمارات العربية المتحدة بسوقها المزدهرة بشكل متزايد من الشركات العالمية والشركات الناشئة الواعدة. ويمكن للكثير منها التباهي بنجاحها الدولي ومنتجاتها الجديرة بالملاحظة....

تونا بينار
الحلول المؤسسية وحلول التوسعة

كيف يمكن ل Java دعم أعمالك التجارية؟

قبل أن نبدأ، أود أن أذكركم بأمر مهم. جافا ليست لغة برمجة فقط.

بارتلوميج كوتشينسكي
الحلول المؤسسية وحلول التوسعة

يوم في حياة مبرمج في شركة The Codest

قد تظن أن جداول عمل المبرمجين لا تختلف عن بعضها البعض. ولكن هذا ليس صحيحاً في الواقع! فلكل شركة ناشئة أو دار برمجيات أو حتى شركة لها جدول عمل خاص بها...

The Codest
بافيل ريبشينسكي Software Engineer

اشترك في قاعدة معارفنا وابقَ على اطلاع على آخر المستجدات في قطاع تكنولوجيا المعلومات.

    نبذة عنا

    The Codest - شركة دولية لتطوير البرمجيات لها مراكز تقنية في بولندا.

    المملكة المتحدة - المقر الرئيسي

    • المكتب 303 ب، 182-184 شارع هاي ستريت نورث E6 2JA
      لندن، إنجلترا

    بولندا - مراكز التكنولوجيا المحلية

    • مجمع مكاتب فابريتشنا المكتبي، أليجا
      بوكوجو 18، 31-564 كراكوف
    • سفارة الأدمغة، كونستروكتورسكا
      11, 02-673 02-673 وارسو، بولندا

      The Codest

    • الصفحة الرئيسية
    • نبذة عنا
    • الخدمات
    • دراسات الحالة
    • اعرف كيف
    • الوظائف
    • القاموس

      الخدمات

    • استشاري
    • تطوير البرمجيات
    • تطوير الواجهة الخلفية
    • تطوير الواجهة الأمامية
    • Staff Augmentation
    • مطورو الواجهة الخلفية
    • مهندسو السحابة
    • مهندسو البيانات
    • أخرى
    • مهندسو ضمان الجودة

      الموارد

    • حقائق وأساطير حول التعاون مع شريك خارجي لتطوير البرمجيات
    • من الولايات المتحدة الأمريكية إلى أوروبا: لماذا تقرر الشركات الأمريكية الناشئة الانتقال إلى أوروبا؟
    • مقارنة مراكز تطوير التكنولوجيا في الخارج: تك أوفشور أوروبا (بولندا)، آسيان (الفلبين)، أوراسيا (تركيا)
    • ما هي أهم التحديات التي تواجه CTOs ومديري تكنولوجيا المعلومات؟
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • شروط استخدام الموقع الإلكتروني

    جميع الحقوق محفوظة © 2025 بواسطة The Codest. جميع الحقوق محفوظة.

    arArabic
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek arArabic