5

Это продолжение к моему вопросу здесь: Android thread runnable performanceAndroid синхронизирован onSensorChanged?

У меня возникли некоторые трудности, обертывание моей головы вокруг синхронизированных метод для моего приложения

Я опрашивает датчики и хранение значений датчиков в массивы, когда они изменить

float[] accelerometerMatrix = new float[3]; 
float[] accelerometerWorldMatrix = new float[3]; 
float[] gyroscopeMatrix = new float[3]; 
float[] gravityMatrix = new float[3]; 
float[] magneticMatrix = new float[3]; 
float[] rotationMatrix = new float[9]; 

class InsertHandler implements Runnable { 
     public void run() { 
      //get values from arrays and insert into db 
     } 
    } 

public void onSensorChanged(SensorEvent event) { 
     sensor = event.sensor; 

     int i = sensor.getType(); 
     if (i == MainActivity.TYPE_ACCELEROMETER) { 
      accelerometerMatrix = event.values; 
     } else if (i == MainActivity.TYPE_GYROSCOPE) { 
      gyroscopeMatrix = event.values; 
     } else if (i == MainActivity.TYPE_GRAVITY) { 
      gravityMatrix = event.values; 
     } else if (i == MainActivity.TYPE_MAGNETIC) { 
      magneticMatrix = event.values; 
     } 

     long curTime = System.currentTimeMillis(); 
     long diffTime = (curTime - lastUpdate); 

     // only allow one update every POLL_FREQUENCY. 
     if(diffTime > POLL_FREQUENCY) { 
      lastUpdate = curTime; 

      //insert into database in background thread 
      executor.execute(insertHandler); 
     } 
    } 

каждые 10мс, мое приложение будет принимать текущие значения датчиков (из массивов) и вставить их в базу данных, используя один поток исполнителя. Таким образом, метод onSensorChanged одновременно писать к массивам, и чтение из массивов записи в базу данных

Мой вопрос, если метод onSensorChanged быть синхронизированы?

Самое главное, что я не пропущу никаких данных. Каждые 10 мс мне нужно сохранить текущие значения датчика - ни один из них не может быть пропущен.

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

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

Но, похоже, что в такой ситуации я не могу вставлять самые последние значения каждые 10 мс. Когда поток пользовательского интерфейса устанавливает блокировку, поток исполнителя не может записать эти значения в базу данных. К тому моменту, когда поток исполнителей может писать, значения теперь будут несколько мс старых и неточно

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

Итак, для такого типа ситуаций, когда мне нужно вставлять самые последние/точные данные датчика каждые 10 мс, следует ли использовать синхронизированный метод?

ответ

2

Ваш текущий код не является потокобезопасным, так как Runnable использует те же массивы, к которым пишет поток пользовательского интерфейса. Как только вы вызываете executor.execute(insertHandler);, нет никакой гарантии, что поток пользовательского интерфейса не получит другого события датчика и изменит одно из значений массива до того, как Runnable будет записывать их в базу данных. Похоже, вы понимаете эту часть.

Чтобы исправить это, я бы не рекомендовал использовать синхронизированный блок вообще, поскольку кажется, что вы просто хотите записать любые значения, хранящиеся в массивах, когда diffTime > POLL_FREQUENCY. Сам метод onSensorChanged(...) будет вызван только в потоке пользовательского интерфейса вашего кода, поэтому вам не придется беспокоиться о том, что другой поток изменит значение массивов в этом методе.

Со всем этим сказано, что вы можете сохранить текущие значения массивов в новом экземпляре вашего класса Runnable. Я знаю, что в предыдущей статье было предложено использовать один и тот же экземпляр, но это не будет иметь заметной разницы. Вы даже можете проверить, открыв Android Monitor и проверив использование вашей памяти в качестве приложения.Сохраняя текущие значения, теперь не имеет значения, будет ли снова вызываться onSensorChanged(), прежде чем вы выберете данные, потому что у вас уже есть копия необходимых вам данных, которые не будут меняться.

Вот что я предлагаю в коде:

class InsertHandler implements Runnable { 
    final float[] accelerometerMatrix; 
    final float[] accelerometerWorldMatrix; 
    final float[] gyroscopeMatrix; 
    final float[] gravityMatrix; 
    final float[] magneticMatrix; 
    final float[] rotationMatrix; 

    public InsertHandler(float[] accelerometerMatrix, float[] accelerometerWorldMatrix, 
      float[] gyroscopeMatrix, float[] gravityMatrix, 
      float[] magneticMatrix, float[] rotationMatrix) { 
     this.accelerometerMatrix = accelerometerMatrix; 
     this.accelerometerWorldMatrix = accelerometerWorldMatrix; 
     this.gyroscopeMatrix = gyroscopeMatrix; 
     this.gravityMatrix = gravityMatrix; 
     this.magneticMatrix = magneticMatrix; 
     this.rotationMatrix = rotationMatrix; 
    } 

    public void run() { 
     // use class field arrays values and insert into db 
    } 
} 

А потом, когда вы добавляете Runnable к executor использования:

Runnable insertHandler = new InsertHandler(accelerometerMatrix, accelerometerWorldMatrix, 
     gyroscopeMatrix, gravityMatrix, magneticMatrix, rotationMatrix); 
executor.execute(insertHandler); 
Смежные вопросы