There might be, but I think this was one of the lessons learned early in Java - data synchronicity is usually not at the container's member function level, but one step above. You should be using synchronisation objects before accessing a non-thread-safe list instead.
Consider:
ThreadSafeQueue tsq;
tsq.push_back(...); // add lots of data
...
// Find the first element that returns true for search_criteria(elem);
auto iter = tsq.find_if(search_criteria);
// (1)
if(iter != tsq.end()) // (2)
{
tsq.erase(iter);
}
In this thread-safe queue, there are still two "gaps" where the queue can be changed by another thread. And, indeed, your iterator may be invalidated by those changes. Now compare:
Queue q;
q.push_back(...); // add lots of data
...
// Create some lock around a pre-existing mutex.
Lock lock(q_mutex);
// Find the first element that returns true for search_criteria(elem);
auto iter = q.find_if(search_criteria);
if(iter != q.end())
{
q.erase(iter);
}
// lock unlocks as it goes out of scope.
Here, because the lock has a larger granularity, it is possible to ensure consistency across the written algorithm.