2015-11-30 5 views
0

У меня есть многопоточная среда в приложении для Android. Я использую одноэлементный класс для хранения данных. Этот одноэлементный класс содержит массив, доступ к которому осуществляется с использованием синхронизированного метода.обнаружить параллельный доступ к синхронной функции java

Приложение использует этот arraylist для рендеринга изображений в приложении.

Первоначальная проблема: Ошибка одновременной модификации, поэтому я сделал функцию get arraylist syncronized.

Текущая задача: Ошибка одновременной модификации не возникает, но между пустым возвратом arraylist (возможно, когда есть параллельный доступ).

Цель: Я хочу определить, когда происходит параллельная модификация, чтобы вместо возвращения пустой arraylist я могу вернуть последнее состояние arraylist.

public synchronized List<FrameData> getCurrentDataToShow() { 
    List<FrameData> lisCurrDataToShow = new ArrayList<FrameData>(); 
    //for (FrameData fd : listFrameData) {//concurrent modification exception 
    //todo iterator test 
    Iterator<FrameData> iterator = listFrameData.iterator(); 
    while (iterator.hasNext()) { 
     FrameData fd = iterator.next(); 
     long currentTimeInMillis = java.lang.System.currentTimeMillis(); 

     if ((currentTimeInMillis > fd.getStartDate().getTime() && currentTimeInMillis < fd.getEndDate().getTime()) || (fd.isAllDay() && DateUtils.isToday(fd.getStartDate().getTime()))) { 
      if (new File(ImageFrameActivity.ROOT_FOLDER_FILES + fd.getFileName()).exists()) { 
       lisCurrDataToShow.add(fd); 
      } 
     } 
    } 
    if (lisCurrDataToShow.size() == 0) { 
     lisCurrDataToShow.add(new FrameData(defaultFileName, null, null, null, String.valueOf(120), false)); 
    } 
    return lisCurrDataToShow; 
} 

Упоминается Detecting concurrent modifications?

Пожалуйста, помогите!

EDIT1:

Эта проблема возникает редко, не каждый раз.

  • Если потоки обращаются к getCurrentDataToShow(), а другой поток пытается получить доступ к этой функции, какова будет функция возврата? Я новичок в многопоточности, пожалуйста, руководство

Edit 2

в OnCreate следующие методы одноточечного называются периодически

DataModelManager.getInstance() getCurrentDataToShow(). DataModelManager.getInstance(). ParseData (responseString);

Полный синглтон класс

public class DataModelManager { 
    private static DataModelManager dataModelManager; 
    private ImageFrameActivity imageFrameAct; 
    private String defaultFileName; 
    public List<FrameData> listFrameData = new ArrayList<FrameData>(); 
// public CopyOnWriteArrayList<FrameData> listFrameData= new CopyOnWriteArrayList<FrameData>(); 
    private String screensaverName; 
    private boolean isToDownloadDeafultFiles; 
    private String tickerMsg = null; 
    private boolean showTicker = false; 
    private boolean showHotspot = false; 
    private String hotspotFileName=null; 
    public String getDefaultFileName() { 
     return defaultFileName; 
    } 
    public boolean isToDownloadDeafultFiles() { 
     return isToDownloadDeafultFiles; 
    } 
    public void setToDownloadDeafultFiles(boolean isToDownloadDeafultFiles) { 
     this.isToDownloadDeafultFiles = isToDownloadDeafultFiles; 
    } 
    private String fileNames; 
    private DataModelManager() { 
    } 
    public static DataModelManager getInstance() { 
     if (dataModelManager == null) { 
      synchronized (DataModelManager.class) { 
       if (dataModelManager == null) { 
        dataModelManager = new DataModelManager(); 
       } 
      } 
     } 
     return dataModelManager; 
    } 
    private synchronized void addImageData(FrameData frameData) { 
     //Log.d("Frame Data","Start date "+frameData.getStartDate()+ " " +"end date "+frameData.getEndDate()); 
     listFrameData.add(frameData); 
    } 
    public synchronized void parseData(String jsonStr) throws JSONException { 
     listFrameData.clear(); 
     if (jsonStr == null) { 
      return; 
     } 
     List<String> listFileNames = new ArrayList<String>(); 
     JSONArray jsonArr = new JSONArray(jsonStr); 
     int length = jsonArr.length(); 
     for (int i = 0; i < length; i++) { 
      JSONObject jsonObj = jsonArr.getJSONObject(i); 
      dataModelManager.addImageData(new FrameData(jsonObj.optString("filename", ""), jsonObj.optString("start", ""), jsonObj.optString("end", ""), jsonObj.optString("filetype", ""), jsonObj.optString("playTime", ""), jsonObj.optBoolean("allDay", false))); 
      listFileNames.add(jsonObj.optString("filename", "")); 
     } 
     fileNames = listFileNames.toString(); 
    } 
    public void setDefaultFileData(String jsonStr) throws JSONException { 
     JSONObject jsonObj = new JSONObject(jsonStr); 
     defaultFileName = jsonObj.optString("default_image", ""); 
     screensaverName = jsonObj.optString("default_screensaver ", ""); 
    } 
    @Override 
    public String toString() { 
     return fileNames.replace("[", "").replace("]", "") + "," + defaultFileName + "," + screensaverName; 
    } 
    public FrameData getFrameData(int index) { 
     return listFrameData.get(index); 
    } 
    public synchronized List<FrameData> getCurrentDataToShow() { 
     List<FrameData> lisCurrDataToShow = new ArrayList<FrameData>(); 
//  for (FrameData fd : listFrameData) {//concurrent modification exception 
      //todo iterator test 
      Iterator<FrameData> iterator = listFrameData.iterator(); 
      while (iterator.hasNext()) { 
       FrameData fd = iterator.next(); 
      long currentTimeInMillis = java.lang.System.currentTimeMillis(); 
      if ((currentTimeInMillis > fd.getStartDate().getTime() && currentTimeInMillis < fd.getEndDate().getTime()) || (fd.isAllDay() && DateUtils.isToday(fd.getStartDate().getTime()))) { 
       if (new File(ImageFrameActivity.ROOT_FOLDER_FILES + fd.getFileName()).exists()) { 
        lisCurrDataToShow.add(fd); 
       } 
      } 
     } 
     if (lisCurrDataToShow.size() == 0) { 
      lisCurrDataToShow.add(new FrameData(defaultFileName, null, null, null, String.valueOf(120), false)); 
     } 
     return lisCurrDataToShow; 
    } 
    public String getCurrentFileNames() { 
     String currFileNames = ""; 
     List<FrameData> currFrameData = getCurrentDataToShow(); 
     for (FrameData data : currFrameData) { 
      currFileNames += "," + data.getFileName(); 
     } 
     return currFileNames; 
    } 
    public ImageFrameActivity getImageFrameAct() { 
     return imageFrameAct; 
    } 
    public void setImageFrameAct(ImageFrameActivity imageFrameAct) { 
     this.imageFrameAct = imageFrameAct; 
    } 

} 
+0

Имеет ли этот метод * эксклюзивный доступ к 'listFrameData'? Вы должны убедиться, что ни один другой метод не может изменить его в одно и то же время, то есть все методы, которые его модифицируют, должны быть синхронизированы на одном мониторе. –

+0

Возможно, вы захотите посмотреть что-то вроде ['CopyOnWriteArrayList'] (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html) для обработки одновременных изменений, например. если «операции обхода значительно превосходят мутации». –

+0

Я пробовал использовать CopyOnWriteArrayList, это приводило к тому, что эта ситуация с пустым arraylist возвращалась чаще. –

ответ

0

Это только часть вашего вопроса, который в настоящее время отвечает:

Если через резьб доступ getCurrentDataToShow(), а другой поток пытается получить доступ к этой функции, что будет ли функция возвращаться?

Это зависит от того, вызывается ли getCurrentDataToShow() на одном и том же целевом объекте; то есть this.

  • Если this одинакова для обоих вызовов, то первый вызов будет завершена до начала второго вызова.

  • Если this отличается, вы будете блокировать различные объекты, и два вызова могут перекрываться.Два потока должны блокировать один и тот же объект для достижения взаимного исключения.

  • В любом случае этот метод не меняет коллекцию listFrameData. Следовательно, неважно, перекрываются ли вызовы! Однако, видимо, что-то еще меняет содержимое коллекции. Если , что код не синхронизирован вообще, или если он синхронизируется с другой блокировкой, то , что может быть источником проблем.

Теперь вы говорите, что вы не видите ConcurrentModificationException «S в данный момент. Это предполагает (но не доказывает), что проблема синхронизации вообще отсутствует. И это предполагает (но не доказывает), что ваша текущая проблема является логической ошибкой.

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

+0

Спасибо за ваш ответ. Я отредактировал свой вопрос и добавил полный класс singleton. Я думаю, что я не могу управлять многопоточной средой с помощью singleton. Я новичок в многопоточности, пожалуйста, руководство –

+0

Я подозреваю, что проблема в том, что 'parseData' иногда вызывается с пустой строкой или строкой, состоящей из пустого массива JSON. Но это все еще не MVCE. Мы не можем запустить этот код, чтобы продемонстрировать проблему. –

Смежные вопросы