Убедитесь, что мой код является потокобезопасным - PullRequest
6 голосов
/ 06 октября 2011

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

Я не уверен на 100% в том, как работает класс Android-обработчиков, поэтому кто-то может подтвердить, что этот код является поточно-ориентированным?

public class MyService extends Service {
    private static final String MESSAGE = "message";

    private final RemoteCallbackList<IMyCallback> readerCallbacks = new RemoteCallbackList<IMyCallback>();

    private static final int REPORT_MSG = 1;

    private Thread readerThread;

    @Override
    public void onCreate() {

        readerThread = new Thread(readerRunnable);
        readerThread.setDaemon(true);
        readerThread.start();

    }

    private Runnable readerRunnable = new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {

                // Blocking call
                byte[] message = JniCommunicator.readMessage();

                if (message == null || message.length == 0) {
                    continue;
                }

                Bundle b = new Bundle();
                b.putByteArray(MESSAGE, message);
                Message m = readHandler.obtainMessage(REPORT_MSG);
                m.setData(b);
                readHandler.sendMessage(m);
            }
        }
    };

    private final Handler readHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
            case REPORT_MSG:

                byte[] message = msg.getData().getByteArray(MESSAGE);

                // Broadcast the new message to all clients
                final int N = readerCallbacks.beginBroadcast();
                for (int i = 0; i < N; i++) {
                    try {
                        readerCallbacks.getBroadcastItem(i).newMessage(message);
                    } catch (RemoteException e) {
                        // The RemoteCallbackList will take care of removing
                        // the dead object for us.
                    }
                }
                readerCallbacks.finishBroadcast();

                break;
            }
        }
    };

        @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private final IService.Stub mBinder = new IService.Stub() {

        public void registerCallback(IMyCallback cb) {
            if (cb != null)
                readerCallbacks.register(cb);
        }

        public void unregisterCallback(IMyCallback cb) {
            if (cb != null)
                readerCallbacks.unregister(cb);
        }
    };
}

В частности, если кто-то вызывает unregisterCallback (), когда обработчик находится в цикле for, произойдет ли сбой?

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

Спасибо

1 Ответ

5 голосов
/ 06 октября 2011

Обработчики являются поточно-ориентированными, что является их полной целью.
Я согласен, что документация по безопасности потоков обработчиков не самая лучшая, но было бы очень забавно, если бы класс, предназначенный для связи между потоками, не был безопасным для потоков.

Что касается удаленных обратных вызовов, они также предназначены для обеспечения безопасности потоков, вам следует прочитать документацию , в ней четко сказано:

Выполняет блокировку базового списка интерфейсов для обработки многопоточных входящих вызовов и поточно-ориентированного способа перебора снимка списка без удержания блокировки

Все, что вам нужно убедиться, это то, что все переменные многопотокового доступа являются поточно-безопасными (что они и есть в вашем случае) и что они не изменяются (ваши являются окончательными, так что здесь тоже не о чем беспокоиться)

...