В устаревшем приложении у меня есть Вектор, который хранит хронологический список файлов для обработки, а несколько потоков запрашивают его для последующего процесса. (Обратите внимание, что я понимаю, что есть, вероятно, лучшие коллекции для использования (не стесняйтесь предлагать), но сейчас у меня нет времени для изменения этой величины.)Нужна консультация по синхронизации Java Vector/ConcurrentModificationException
В заданный промежуток времени другой поток проверяет рабочий каталог, чтобы увидеть, остались ли какие-либо файлы сиротами, потому что что-то пошло не так. Метод, вызываемый этим потоком, иногда выдает исключение ConcurrentModificationException, если система ненормально занята. Поэтому я знаю, что по крайней мере два потока пытаются использовать вектор сразу.
Вот код. Я считаю, что проблема заключается в использовании клона() для возвращаемого вектора.
private synchronized boolean isFileInDataStore(File fileToCheck){
boolean inFile = false;
for(File wf : (Vector<File>)m_dataStore.getFileList().clone()){
File zipName = new File(Tools.replaceFileExtension(fileToCheck.getAbsolutePath(), ZIP_EXTENSION));
if(wf.getAbsolutePath().equals(zipName.getAbsolutePath())){
inFile = true;
break;
}
}
return inFile;
}
Метод
GetFileList() выглядит следующим образом:public synchronized Vector<File> getFileList() {
synchronized(fileList){
return fileList;
}
}
Как быстро исправить, было бы изменить метод GetFileList вернуть копию вектора следующим образом хватает?
public synchronized Vector<File> getFileListCopy() {
synchronized(fileList){
return (Vector<File>)fileList.clone();
}
}
Я должен признать, что я обычно путают с использованием синхронизированных в Java, как она относится к коллекциям, а просто объявить метод как таковой не достаточно. Как вопрос бонуса, объявляет метод как синхронизированный и обертывает обратный вызов другим синхронизированным блоком, просто сумасшедшим кодированием? Выглядит излишне.
EDIT: Ниже приведены другие методы, которые касаются списка.
public synchronized boolean addFile(File aFile) {
boolean added = false;
synchronized(fileList){
if(!fileList.contains(aFile)){
added = fileList.add(aFile);
}
}
notifyAll();
return added;
}
public synchronized void removeFile(File dirToImport, File aFile) {
if(aFile!=null){
synchronized(fileList){
fileList.remove(aFile);
}
// Create a dummy list so I can synchronize it.
List<File> zipFiles = new ArrayList<File>();
synchronized(zipFiles){
// Populate with actual list
zipFiles = (List<File>)diodeTable.get(dirToImport);
if(zipFiles!=null){
zipFiles.remove(aFile);
// Repopulate list if the number falls below the number of importer threads.
if(zipFiles.size()<importerThreadCount){
diodeTable.put(dirToImport, getFileList(dirToImport));
}
}
}
notifyAll();
}
}
На какой линии выбрасывается исключение? – Jivings
Трудно сказать. Основываясь исключительно на коде, который вы указали, изменение getFileList для возврата клона не помогло бы, потому что в единственном месте, где вы используете getFileList, оно уже создает клон. Всегда возвращающийся клон может улучшить ситуацию (но нет никаких доказательств того, будет это или нет, на основе кода, который вы опубликовали. Т.е. вы не показывали всю программу.) –
@ Повреждения - это бросается в цикл 'for (Файл wf: (Вектор) m_dataStore.getFileList(). clone()) {' –
user1011251