Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
需要关于Java Vector/ConcurrentModificationException同步的建议吗_Java - Fatal编程技术网

需要关于Java Vector/ConcurrentModificationException同步的建议吗

需要关于Java Vector/ConcurrentModificationException同步的建议吗,java,Java,在遗留应用程序中,我有一个向量,它按时间顺序列出要处理的文件,多个线程要求它处理下一个文件。(请注意,我意识到可能有更好的收藏可供使用(请随意提出建议),但我现在没有时间进行如此大规模的更改。) 在一个预定的时间间隔内,另一个线程检查工作目录,以查看是否有任何文件由于出现问题而被孤立。如果系统异常繁忙,此线程调用的方法偶尔会抛出ConcurrentModificationException。所以我知道至少有两个线程试图同时使用向量 这是代码。我认为问题在于在返回的向量上使用clone() pri

在遗留应用程序中,我有一个向量,它按时间顺序列出要处理的文件,多个线程要求它处理下一个文件。(请注意,我意识到可能有更好的收藏可供使用(请随意提出建议),但我现在没有时间进行如此大规模的更改。)

在一个预定的时间间隔内,另一个线程检查工作目录,以查看是否有任何文件由于出现问题而被孤立。如果系统异常繁忙,此线程调用的方法偶尔会抛出ConcurrentModificationException。所以我知道至少有两个线程试图同时使用向量

这是代码。我认为问题在于在返回的向量上使用clone()

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;
}
private synchronized boolean isFileInDataStore(文件fileToCheck){
布尔内嵌=假;
对于(文件wf:(Vector)m_dataStore.getFileList().clone()){
File zipName=新文件(Tools.replaceFileExtension(fileToCheck.getAbsolutePath(),ZIP_扩展名));
如果(wf.getAbsolutePath().equals(zipName.getAbsolutePath())){
infle=true;
打破
}
}
返回填充;
}
getFileList()方法如下所示:

public synchronized Vector<File> getFileList() {
    synchronized(fileList){
        return fileList;
    }
}
公共同步向量getFileList(){ 已同步(文件列表){ 返回文件列表; } } 作为一个快速解决方案,更改getFileList方法以返回向量的副本(如下所示)就足够了吗

public synchronized Vector<File> getFileListCopy() {
    synchronized(fileList){
        return (Vector<File>)fileList.clone();
    }
}
公共同步向量getFileListCopy(){
已同步(文件列表){
return(Vector)fileList.clone();
}
}
我必须承认,在Java中使用synchronized通常会让我感到困惑,因为它与集合有关,仅仅声明方法本身是不够的。作为一个额外的问题,将方法声明为synchronized并用另一个synchronized块包装返回调用是否只是疯狂的编码?看起来多余

编辑:以下是与列表相关的其他方法

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();
    }
}
public synchronized boolean addFile(文件aFile){
布尔加法=假;
已同步(文件列表){
如果(!fileList.contains(aFile)){
added=fileList.add(文件);
}
}
notifyAll();
增加了退货;
}
公共同步的void removeFile(文件dirToImport,文件aFile){
if(aFile!=null){
已同步(文件列表){
文件列表。删除(文件);
}
//创建一个虚拟列表,以便我可以同步它。
List zipFiles=new ArrayList();
同步(zipFiles){
//用实际列表填充
zipFiles=(List)diodeTable.get(dirToImport);
if(zipFiles!=null){
zipFiles.移除(aFile);
//如果数量低于导入器线程的数量,请重新填充列表。

如果(zipFiles.size()m_数据存储在哪里更新?如果不同步,这很可能是罪魁祸首。

基本上,这里有两个独立的问题:同步化和ConcurrentModificationException。
Vector
与例如
ArrayList
相反,它是在内部同步的,因此像
add()这样的基本操作是同步的
get()
不需要同步。但是,如果您在
向量
上迭代并同时修改它(例如,通过插入元素),您甚至可以从单个线程获得
ConcurrentModificationException
。因此,如果您在
for
循环中执行了修改操作,您可以中断
向量
>即使只有一个线程。现在,如果您在类外返回
向量
,您不会阻止任何人在代码中没有正确同步的情况下修改它。原始版本的
getFileList()中的
fileList
上的同步
是毫无意义的。返回副本而不是原件可能会有所帮助,使用允许在迭代时进行修改的集合也可能会有所帮助,例如(但请注意修改的额外成本,在某些情况下,这可能会成为一种阻碍)

“在Java中使用synchronized通常会让我感到困惑 属于集合,因为简单地声明方法本身是不正确的 够了”

正确。
synchronized
在一个方法上意味着一次只能有一个线程进入该方法。但是如果同一个集合可以从多个方法中看到,那么这没有多大帮助

为了防止两个线程同时访问同一个集合,它们需要在同一对象上进行同步,例如集合本身。您在某些方法中已经进行了同步,但是
isFileInDataStore
似乎访问了由
getFileList
返回的集合,而没有对其进行同步

请注意,像您在
getFileList
中所做的那样,以同步方式获取集合是不够的-需要同步的是访问。如果您只需要读取访问,克隆集合(可能)会解决此问题


除了查看同步,我建议您跟踪涉及哪些线程-例如,打印出异常的调用堆栈和/或使用调试器。最好真正了解发生了什么,而不是只是同步和克隆,直到错误消失!

首先,您应该将逻辑移到m_数据的任何类如果没有,请存储。

完成此操作后,将列表设置为最终列表,并仅在修改其元素时对其进行同步。只需要读取它的线程不需要同步访问。它们可能最终轮询过时的列表,但我认为这不是问题。这可以提高性能

据我所知,您只需要在添加和删除时进行同步,并且只需要锁定列表

e、 g

一揽子答复

导入java.util.logging.Level; 导入java.util.logging.Logger

公开课范例{

public static void main(String[] args)
{
    Example c = new Example();
    c.runit();
}


public void runit()
{
    Thread.currentThread().setName("Thread-1");

    new Thread("Thread-2")
    {
        @Override
        public void run() {               
            test1(true);
        }            
    }.start();

    // Force a scenario where Thread-1 allows Thread-2 to acquire the lock
    try {
        Thread.sleep(1000);
    } catch (InterruptedException ex) {
        Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
    }

    // At this point, Thread-2 has acquired the lock, but it has entered its wait() method, releasing the lock

    test1(false);
}

public synchronized void test1(boolean wait)    
{
    System.out.println( Thread.currentThread().getName() +  " : Starting...");
    try {
        if (wait)
        {
            // Apparently the current thread is supposed to wait for some other thread to do something...
            wait();
        } else {
            // The current thread is supposed to keep running with the lock
            doSomeWorkThatRequiresALockLikeRemoveOrAdd();
            System.out.println( Thread.currentThread().getName() +  " : Our work is done. About to wake up the other thread(s) in 2s...");
            Thread.sleep(2000);

            // Tell Thread-2 that it we have done our work and that they don't have to spare the CPU anymore.
            // This essentially tells it "hey don't wait anymore, start checking if you can get the lock"
            // Try commenting this line and you will see that Thread-2 never wakes up...
            notifyAll();

            // This should show you that Thread-1 will still have the lock at this point (even after calling notifyAll).
            //Thread-2 will not print "after wait/notify" for as long as Thread-1 is running this method. The lock is still owned by Thread-1.
            Thread.sleep(1000);
        }


        System.out.println( Thread.currentThread().getName() +  " : after wait/notify");
    } catch (InterruptedException ex) {
        Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private void doSomeWorkThatRequiresALockLikeRemoveOrAdd()
{
    // Do some work that requires a lock like remove or add
}