【问题标题】:Concurrent Modification Exception, despite waiting for finish并发修改异常,尽管等待完成
【发布时间】:2013-04-20 05:47:32
【问题描述】:

这是我的 onCreate 的一部分,有时会导致异常:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_tilisting);
    _context = getApplicationContext();
    SDName = Environment.getExternalStorageDirectory();
    //listview = (ListView)findViewById(R.id.TIlistview);
    String TIdir = new File(SDName, "/TitaniumBackup/").toString();
    final ArrayList<String> apps = new ArrayList<String>();
    final StringBuffer done = new StringBuffer();
    Command command = new Command(0,"ls -a "+TIdir+"/*.properties") {
        @Override
        public void output(int arg0, String arg1) {
            synchronized(apps) {
                apps.add(arg1);
                if (!done.toString().equals("")) {
                    done.append("done");//oh no
                }
            }
        }
    };
    try {
        RootTools.getShell(true).add(command).waitForFinish();
        String attrLine = "";
        int ind;
        backups = new ArrayList<TIBackup>();
        synchronized(apps) {
            for (String app : apps) {
                try {
                    TIBackup bkup = new TIBackup(app);
                    FileInputStream fstream = new FileInputStream(app);
                    BufferedReader atts = new BufferedReader(new InputStreamReader(fstream));
                    while ((attrLine = atts.readLine()) != null) {
                        ind = attrLine.indexOf('=');
                        if (ind !=-1 && !attrLine.substring(0,1).equals("#"))
                        bkup.prop.put(attrLine.substring(0,ind), attrLine.substring(ind+1));
                    }
                    backups.add(bkup);
                    atts.close();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            done.append("done");
        }
        setListAdapter( new StableArrayAdapter(this,backups));
    } catch (InterruptedException e) {
        //TODO:errors
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (TimeoutException e) {
        e.printStackTrace();
    }

for (String app : apps) { 导致异常,尽管它之前有 waitforfinish()。

这个更新的代码应该修复它,从输出中添加数据,并等待主代码中同步的任何落后者,但如果你在上面的 //oh no 行设置断点,它仍然会到达这个在 UI 主代码运行后尝试添加项目的点。所以 waitforfinish() 不是在等待吗?如何防止这种竞争状况?

我也尝试了下面的RootTask 代码,但它似乎停在了最后一行?

    RootTask getProfile = new RootTask() {
        @Override
        public void onPostExecute(ArrayList<String> result) {
            super.onPostExecute(result);
            for (String r : result) {
                System.out.println(r);
            }
        }
    };
    getProfile.execute("ls /data/data/org.mozilla.firefox/files/mozilla/" );

onPostExecute 永远不会运行。

【问题讨论】:

  • 请不要使用 DataInputStream 读取文本。这是多余的和令人困惑的。请从您的示例中删除它,因为此错误代码被大量复制。

标签: java android inputstream concurrentmodification roottools


【解决方案1】:

这部分是由 RootTools 中的设计缺陷造成的。我认为问题的症结在于您在 shell 上执行的操作比为 shell 命令设置的默认超时时间要长。当超时发生时,它只是将命令返回为已完成,这就是设计缺陷所在。

我提供了一个新的 jar 以供使用,以及一些关于此的更多信息。我也弃用了 waitForFinish(),因为我同意它曾经是并且现在是一个糟糕的解决方案。

https://code.google.com/p/roottools/issues/detail?id=35

如果您有任何疑问或问题,请告诉我:)

【讨论】:

    【解决方案2】:

    Output() 将被调用 waitForFinish() 等待。实现命令执行的代码有问题。

    最有可能:命令执行器 (RootTools ?) 在 shell 上运行命令,得到一堆输出行,通知调用线程等待,然后 然后 调用命令的 output()对于它作为输出的每一行。我认为它应该通知命令线程 output() 已在命令对象上被调用,对于所有输出行。

    您仍然可以将列表修改代码和列表迭代代码包装在synchronized(&lt;some common object&gt;){} 中。

    更新:

    所以waitForFinish() 不等待?如何防止这种竞争状况?

    它会等待,但不会等待您的代码。 Synchronized 关键字只是确保在迭代 apps 集合时不会同时调用 Command 对象的 output()。它安排两个线程按特定顺序运行。

    恕我直言,waitForFinish() 不是一个好的模式,使调用线程等待破坏了单独执行程序的意义。最好将其表述为 AsyncTask 或为每个 Command 对象接受一个事件侦听器。

    只是一个粗略的例子,这个类:

    public class RootTask extends AsyncTask<String,Void,List<String>> {
        private boolean mSuccess;
    
        public boolean isSuccess() {
            return mSuccess;
        }
    
        @Override
        protected List<String> doInBackground(String... strings) {
            List<String> lines = new ArrayList<String>();
    
            try {
                Process p = Runtime.getRuntime().exec("su");
                InputStream is = p.getInputStream();
                OutputStream os = p.getOutputStream();
    
                os.write((strings[0] + "\n").getBytes());
    
                BufferedReader rd = new BufferedReader(new InputStreamReader(is));
    
                String line;
    
                while ((line = rd.readLine()) != null){
                    lines.add(line);
                }
    
                mSuccess = true;
                os.write(("exit\n").getBytes());
                p.destroy();
    
            } catch (IOException e) {
                mSuccess = false;
                e.printStackTrace();
            }
    
            return lines;
        }
    }
    

    可以用作:

    RootTask listTask = new RootTask{
      @Override
      public void onPostExecute(List<String> result){
          super.onPostExecute();
          apps.addAll(result);
          //-- or process the results strings--
      }
    };
    
    listTask.execute("ls -a "+TIdir+"/*.properties");
    

    【讨论】:

    • 好点,我记得在线程中使用同步,没想到这是线程问题。即使添加了同步,我也遇到了另一个问题 - 请参阅更新后的问题。
    • 谢谢,但是当我尝试替换此代码时,不会调用 onResult。我试过onPostExecute,它也没有被调用。它似乎默默地失败了,它可以在doInBackground中println(line),但永远不会触发循环之后的断点。
    • @NoBugs 它的onPostExecute() 我已经更新了代码。您的问题表明进程的外流被阻塞,readLine() 一直等待永远。你在运行什么命令?
    • 我都试过了,它似乎不起作用,即使我正在做一个简单的ls。请参阅上面的更新
    猜你喜欢
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 2020-10-04
    • 2016-11-19
    • 2021-12-10
    • 2019-05-31
    相关资源
    最近更新 更多