سؤال

أنا لا أحب قفل الرمز الخاص بي متزامنة (هذا), ، لذلك أنا أجرى مع استخدام atomicbooleans.. وبعد في مقتطف التعليمات البرمجية، xmppconnectionIf.connect () يجعل اتصال مأخذ توصيل بخادم بعيد. لاحظ أن المتغير _توصيل يستخدم فقط في أي وقت مضى في الاتصال() طريقة؛ بينما _Connected. يستخدم في كل طرق أخرى تحتاج إلى استخدام _xmppconn.. وبعد أسئلتي مدرجة بعد مقتطف التعليمات البرمجية أدناه.

private final AtomicBoolean _connecting = new AtomicBoolean( false );
private final AtomicBoolean _connected = new AtomicBoolean( false ); 
private final AtomicBoolean _shuttingDown = new AtomicBoolean( false ); 
private XMPPConnection _xmppConn;
/**
 * @throws XMPPFault if failed to connect
 */
public void connect() 
{
    // 1) you can only connect once
    if( _connected.get() )
        return;

    // 2) if we're in the middle of completing a connection, 
    //    you're out of luck
    if( _connecting.compareAndSet( false, true ) )
    {
        XMPPConnectionIF aXmppConnection = _xmppConnProvider.get();
        boolean encounteredFault = false;

        try
        {
            aXmppConnection.connect(); // may throw XMPPException
            aXmppConnection.login( "user", "password" ); // may throw XMPPException
            _connected.compareAndSet( false, true );
            _xmppConn = aXmppConnection;
        }
        catch( XMPPException xmppe )
        {
            encounteredFault = true;
            throw new XMPPFault( "failed due to", xmppe );
        }
        finally
        {
            if( encounteredFault )
            {
                _connected.set( false );
                _connecting.set( false );
            }
            else
                _connecting.compareAndSet( true, false );
        }
    }
}
  1. استنادا إلى التعليمات البرمجية، هل هو خيط آمن في النقطة التي تحاول 2 خيوط الاتصال الاتصال() في الوقت نفسه، يسمح فقط بمحاولة اتصال واحدة فقط.

  2. في Blue Block، أنا أعمل اثنين من AtomicBoolean.Set (..) في الخلافة، ستكون هناك مشكلة، حيث أثناء الفجوة بين هذه المكالمات الذرية 2، قد تتصل بعض المواضيع _Connected.get () بطرق أخرى؟

  3. عند استخدام _xmppconn., ، يجب أن أفعل متزامنة (_xmppconn) ?

تحديث وأضاف مفقود تسجيل الدخول مكالمة في الطريقة.

هل كانت مفيدة؟

المحلول

  1. نعم. يعمل المتغير _Connecting كقفل اختبار ومجموعة يمنع محاولات اتصال متزامنة متعددة.

  2. لا مشكلة - حتى إذا كان مؤشر ترابط آخر يقرأ بين الكتابة، فسوف يمنعه _Connecting من محاولة الاتصال بشكل متزامن.

  3. نعم، على افتراض أن أساليبها ليست آمنة بالفعل.

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

نصائح أخرى

ضع في اعتبارك أن استخدام 3 AtomicBooleanS هو ليس نفس الحذر من المتغيرات الثلاثة مع قفل واحد. يبدو لي مثل حالة تلك المتغيرات تشكل حالة واحدة من الكائن، وبالتالي ينبغي حرمانها من قبل نفس القفل. في التعليمات البرمجية الخاصة بك باستخدام المتغيرات الذرية، من الممكن أن تكون مؤشرات الترابط المختلفة لتحديث حالة _connected, _connecting, ، و _shuttingDown بشكل مستقل - استخدام المتغيرات الذرية سيضمن فقط إمكانية الوصول إلى نفس متزامنة المتغير بين مؤشرات الترابط متعددة.

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

class Thing {
  Boolean connected;
  Boolean connecting;
  Boolean shuttingDown;
  Object connectionStateLock = new Object();

  void connect() {
    synchronized (connectionStateLock) {
      // do something with the connection state.
    }
  }

  void someOtherMethodThatLeavesConnectionStateAlone() {
    // free range thing-doing, without getting a lock on anything.
  }
}

إذا كنت تقوم بالبرمجة المتزامنة في جافا، فسأوصي بشدة بالقراءة جافا تزامن في الممارسة.

أعتقد أن الآخرين يغطون صحة بشكل كاف في تعليقاتهم. سيكون تعليقي الإضافي الوحيد هو أنني أشعر بالقلق قليلا عن موضع الإصدار في النهاية. يبدو أنك قد ترغب حقا في التفاف الكتلة بأكملها هناك (بما في ذلك مكالمة _xmppconnprovider.get ()) في تجربة {} أخيرا {} التي من شأنها أن تضمن أنك ستطلق دائما القفل. خلاف ذلك، يمكن أن يحدث نوع من الاستثناء غير المعدل فيه وأتركك في حالة غير مستعملة.

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

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

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

وجهة نظري هي أن هذا النوع من القفل الذي تحاول القيام به هو صعب للغاية للحصول على حق. العصا بمزامنة أو استخدام الأقفال في java.util.concurrent.locks. صفقة.

  1. نعم انها راضية بالتأكيد. كما _Connecting.comParEndeNDSET (FALSE، TRUE) سيسمح لخيط واحد فقط بالدخول.

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

  3. نعم إذا كان xmppconn غير آمن للخطر.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top