Неправильное использование synchronized?

#java #android #multithreading #facebook-graph-api #synchronized

#java #Android #многопоточность #facebook-graph-api #синхронизированный

Вопрос:

Я пытаюсь синхронизировать два блока кода для приложения Android.

Первый блок использует AsyncFacebookRunner для выполнения запроса интересов пользователя, если таковые имеются.

Если интересы были обнаружены, переменная-член для этого пользователя заполняется их интересами из ответа Facebook JSON.

Второй блок кода проверяет, действительно ли у пользователя есть интересы, просматривая эту переменную-член. Если есть интересы, выполняется несколько дополнительных строк кода.

 synchronized(this)
{
    if ( (friend.getmActivities().length() == 0) amp;amp; (friend.getmInterests().length() == 0) )
        friend.requestInterests(mFacebook); // Get that friend's Facebook activities and interests.
}

synchronized(this)
{
    if ( (friend.getmActivities().length() == 0) amp;amp; (friend.getmInterests().length() == 0) )
    {
        final AlertDialog alertDialog = new AlertDialog.Builder(mContext).create();
        alertDialog.setTitle("Sorry...");
        alertDialog.setMessage("Your friend isn't sharing their interests.");
        alertDialog.setButton("Go Back", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                alertDialog.dismiss();
            }
        });

        alertDialog.show();
    }
}
  

Я хочу, чтобы второй блок дождался завершения friend.requestInterests() перед выполнением.

РЕДАКТИРОВАТЬ: В итоге я реструктурировал свой код, чтобы использовать метод onComplete от runner. Все это произошло, когда я изменил структуру своей программы и должен был изменить все. Спасибо всем за помощь.

Комментарии:

1. AysncFacebookRunner должен поддерживать обратные вызовы. Используйте их (а если это не так, … найдите библиотеку получше? :-). Тогда это просто вопрос реакции на событие «complete», очень похожее на обычный щелчок кнопки или что-то еще. В зависимости от точных деталей (например, в каком потоке выполняется отправка), то synchronized все еще может потребоваться. Однако это ужасное неправильное использование, которое, вероятно, даже не делает желаемого. Рассмотрим другие «примитивы», такие как мьютексы или семафоры для управления ресурсами «вне области видимости». (Также смотрите Фьючерсы и т.д.)

2. Это правда. Однако я бы предпочел сделать это без использования обратного вызова. Мне пришлось бы довольно сильно изменить структуру моего кода, чтобы использовать onComplete.

Ответ №1:

Я хочу, чтобы второй блок дождался завершения friend.requestInterests() перед выполнением.

JVM гарантирует, что два блока не выполняются одновременно для одного и того же экземпляра this.

Если вы дополнительно хотите убедиться, что второй блок запускается только после выполнения первого, то вы можете сделать это, используя переменную состояния и wait / notify вызовы. Но лучший способ — использовать один из классов синхронизации, таких CountDownLatch ; например

 private CountDownLatch latch = new CountDownLatch(1);

...

synchronized(this) {
   // do first actions
}
this.latch.countdown();

....

this.latch.await();
synchronized(this) {
    // do second
}
  

Действительно, если это единственные места, где осуществляется доступ к соответствующему состоянию объекта и оно обновляется, вы должны быть в состоянии обойтись без synchronized блоков. Вызовы countdown и await обеспечат необходимую связь «предшествует» для обеспечения надлежащей синхронизации.


Однако комментарий @pst поднимает вопрос о том, что, возможно, существует лучший способ сделать это с использованием API Facebook library framework, который использует ваш код.