0

I have a HashMap of Sound objects

private HashMap<Integer, Sound> sounds;

over which I'm trying to iterate to turn off all the sounds. I used this answer to create an Iterator, but I'm still getting ConcurrentModificationException, though I'm sure there's no other code calling this at the same time.

public synchronized final void stopAll() {
    Iterator<Entry<Integer, Sound>> soundEntries = sounds.entrySet().iterator();
    while(soundEntries.hasNext())
    {
        Entry<Integer, Sound> s = soundEntries.next();
        s.getValue().myOnCompletionListener = null;
        s.getValue().fadeYourself();
    }
    sounds.clear();
}

In what way should I rewrite this to keep the ConcurrentModificationException from happening?

This is inside my Sound class:

    private class soundFader extends AsyncTask<Sound, Void, Void>
    {
        @Override
        protected Void doInBackground(Sound... arg0) {
            arg0[0].fadeOut();
            return null;
        }
    }

    private void fadeOut()
    {
        float STEP_DOWN = (float) 0.10;
        float currentVol = myVolume;
        float targetVol = 0;
        if(isSoundEnabled())
        {
            while(currentVol > targetVol)
            {
                currentVol -= STEP_DOWN;
                mp.setVolume(currentVol, currentVol);
                try {
                    Thread.sleep(70);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        mp.setVolume(0, 0);
        onCompletion(mp);
        sounds.remove(resource);    // THIS LINE WAS MY ERROR
        mp.seekTo(0);
        nowPlaying = false;
    }

    public void fadeYourself()
    {
        soundFader fader = new soundFader();
        fader.execute(this);
    }
Community
  • 1
  • 1
Thunder Rabbit
  • 5,405
  • 8
  • 44
  • 82

1 Answers1

0

It is not permissible for one thread to modify a Collection while another thread is iterating over it.

If you want to modify only values (not keys) there is no need to use iterators here.

public synchronized final void stopAll() {
    for(Sound s: sounds.values())
    {
        s.myOnCompletionListener = null;
        s.fadeYourself();
    }
    sounds.clear();
}

Ninja edit:
You are removing items from the Collection while iterating. Hence the CoMo exception. Since you are doing sounds.clear(); towards the end, you can remove the sounds.remove(resource); line.

CSchulz
  • 10,882
  • 11
  • 60
  • 114
Reno
  • 33,594
  • 11
  • 89
  • 102