检测对同步函数java的并发访问
我在android应用程序中有一个多线程环境。我使用单例类来存储数据。此singleton类包含一个arraylist,可使用同步方法访问该arraylist 应用程序使用此arraylist在应用程序中渲染图像 最初的问题:并发修改错误经常出现,所以我使GetArrayList函数同步化 当前问题:并发修改错误未出现,但介于返回的空arraylist之间,可能是在存在并发访问时返回的 目标:我想检测并发修改的时间,这样就可以返回arraylist的最后一个状态,而不是返回空的arraylist检测对同步函数java的并发访问,java,android,multithreading,arraylist,concurrency,Java,Android,Multithreading,Arraylist,Concurrency,我在android应用程序中有一个多线程环境。我使用单例类来存储数据。此singleton类包含一个arraylist,可使用同步方法访问该arraylist 应用程序使用此arraylist在应用程序中渲染图像 最初的问题:并发修改错误经常出现,所以我使GetArrayList函数同步化 当前问题:并发修改错误未出现,但介于返回的空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.parseDataresponseString
完全单例类
这是您问题中目前唯一可以回答的部分: 如果一个线程正在访问getCurrentDataToShow,而另一个线程试图访问该函数,该函数将返回什么 这取决于是否在同一目标对象上调用getCurrentDataToShow;i、 这是什么 如果这两个调用相同,则第一个调用将在第二个调用开始之前完成 如果这是不同的,您将锁定不同的对象,这两个调用可能重叠。两个线程需要锁定同一个对象以实现互斥 无论哪种情况,此方法都不会更改listFrameData集合。因此,调用是否重叠并不重要!然而,显然还有其他东西正在改变收藏的内容。如果该代码根本没有同步,或者正在另一个锁上同步,那么这可能是问题的根源 现在你说你现在没有看到ConcurrentModificationException。这表明,但并不能证明根本不存在同步问题。这表明但不能证明你目前的问题是一个逻辑错误
但正如我在上面所评论的,有理由怀疑您向我们展示的代码是否真实反映了您的真实代码。如果需要更明确的诊断,则需要提供MVCE。此方法是否具有对listFrameData的独占访问权限?您需要确保没有其他方法可以同时修改它,即所有修改它的方法都需要在同一个监视器上同步。您可能希望查看类似于处理并发修改的内容,例如,如果遍历操作的数量远远超过了突变。我试着使用CopyOnWriteArrayList,它导致了这种空arraylist返回频率更高的情况,我希望您得到ConcurrentModificationException,无论您使用显式迭代器还是增强型for语句,因为后者是前者的语法糖。你确定你的列表不是空的吗?是否正在为listFrameData的某个位置指定新值?是。我肯定名单不是空的。如果lisCurrDataToShow.size==0{/..}正在运行,则当this函数未同步时,立即引发并发修改。可能由于其他线程正在访问arraylist,因此未访问arraylist。感谢您的响应。我已经编辑了我的问题并添加了完整的singleton类。我认为我无法使用singleton管理多线程环境。我是多线程方面的新手,我怀疑问题在于有时使用空字符串或由空JSON数组组成的字符串调用parseData。但这仍然不是一个MVCE。我们无法运行此代码来演示问题。
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;
}
}