簡體   English   中英

檢測對同步功能Java的並發訪問

[英]detect concurrent access to syncronized function java

我在android應用中有一個多線程環境。 我使用單例類來存儲數據。 這個單例類包含一個使用同步方法訪問的arraylist。

應用程序使用此arraylist在應用程序中渲染圖像。

最初的問題 :並發修改錯誤來了,所以我使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;
}

檢測並發修改?

請幫忙!

編輯1:

並非每次都很少發生此問題。

  • 如果一個線程正在訪問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;
    }

}

這是您的問題中目前唯一可以回答的部分:

如果一個線程正在訪問getCurrentDataToShow()而另一個線程試圖訪問該函數,則該函數將返回什么?

這取決於您是否在同一目標對象上調用getCurrentDataToShow() this是什么。

  • 如果this是兩個調用相同,則第二個呼叫開始前的第一個電話將完成。

  • 如果this是不同的,你會被鎖定在不同的對象,並在這兩個電話可以重疊。 兩個線程需要鎖定同一對象才能實現互斥。

  • 無論哪種情況,此方法都不會更改listFrameData集合。 因此,電話是否重疊都沒關系! 但是,顯然還有其他事情正在改變集合的內容。 如果代碼是不同步的全部,或者如果它是在一個不同的鎖同步,那么可能是問題的根源。

現在您說您現在看不到ConcurrentModificationException 這表明(但不能證明)根本沒有同步問題。 這表明(但不能證明)您當前的問題是邏輯錯誤。

但是(正如我在上面評論的那樣),我們有理由懷疑您向我們展示的代碼是否真實反映了您的真實代碼。 如果要進行更明確的診斷,則需要提供MVCE。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM