检测同步函数java

时间:2015-11-30 08:24:01

标签: java android multithreading arraylist concurrency

我在Android应用程序中有一个多线程环境。我使用单例类来存储数据。这个单例类包含一个使用synchronized方法访问的arraylist。

应用程序使用此arraylist在app中呈现图像。

初始问题:出现并发修改错误,所以我使get arraylist函数同步。

当前问题:并发修改错误未发生但返回空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()并且另一个线程试图访问此函数,那么该函数将返回什么?我是多线程的新手,请指导

修改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;
    }

}

1 个答案:

答案 0 :(得分:0)

这是您目前唯一可回答问题的部分:

  

如果线程正在访问getCurrentDataToShow()并且另一个线程试图访问此函数,该函数将返回什么?

这取决于您是否在同一目标对象上调用getCurrentDataToShow();即this是什么。

  • 如果两个电话的this相同,则第一个电话会在第二个电话开始前完成。

  • 如果this不同,您将锁定不同的对象,这两个调用可能会重叠。两个线程需要锁定同一个对象才能实现互斥。

  • 在任何一种情况下,此方法都不会更改listFrameData集合。因此,呼叫是否重叠并不重要!但是,显然别的东西正在改变集合的内容。如果代码根本没有同步,或者它正在同一个不同的锁上同步,则 可能是问题的根源。

现在你说你目前没有看到ConcurrentModificationException。这表明(但未证明)根本没有同步问题。这表明(但未证明)您当前的问题是一个逻辑错误。

但是(正如我上面评论的那样)有理由怀疑你向我们展示的代码是对你真实代码的真实反映。如果您想要更明确的诊断,则需要提供MVCE。