I've got an ArrayList which is being instantiated and populated on the background thread (I use it to store the Cursor data). At the same time it can be accessed on the main thread and iterated through using foreach. So this obviously may result in throwing an exception.
My question is what's the best practice to make this class field thread-safe without copying it every time or using flags?
class SomeClass {
private final Context mContext;
private List<String> mList = null;
SomeClass(Context context) {
mContext = context;
}
public void populateList() {
new Thread(new Runnable() {
#Override
public void run() {
mList = new ArrayList<>();
Cursor cursor = mContext.getContentResolver().query(
DataProvider.CONTENT_URI, null, null, null, null);
try {
while (cursor.moveToNext()) {
mList.add(cursor.getString(cursor.getColumnIndex(DataProvider.NAME)));
}
} catch (Exception e) {
Log.e("Error", e.getMessage(), e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}).start();
}
public boolean searchList(String query) { // Invoked on the main thread
if (mList != null) {
for (String name : mList) {
if (name.equals(query) {
return true;
}
}
}
return false;
}
}
In general it is a very bad idea to operate concurrently on a datastructure that is not thread-safe. You have no guarantee that the implementation will not change in the future, which may severly impact the runtime behavior of the application, i.e. java.util.HashMap causes infinite loops when being concurrently modified.
For accessing a List concurrently, Java provides the java.util.concurrent.CopyOnWriteArrayList. Using this implementation will solve your problem in various ways:
it is thread safe, allowing concurrent modifications
iterating over snapshots of the list is not affected by concurrent add operations, allowing concurrently adding and iterating
it's faster than synchronization
Alternatively, if not using a copy of the internal array is a strict requirement (which I can't imagine in your case, the array is rather small as it only contains object references, which can be copied in memory quite efficiently), you may synchronize the access on the map.
But that would require the Map to be initialized properly, otherwise your code may throw a NullPointerException because the order of thread-execution is not guaranteed (you assume the populateList() is started before, so the list gets initialized.
When using a synchronized block, choose the protected block wisely. In case you have the entire content of the run() method in a synchronized block, the reader thread has to wait until the results from the cursor are processed - which may take a while - so you actually loose all concurrency.
If you decide to go for the synchronized block, I'd make the following changes (and I don't claim, they are perfectly correct):
Initialize the list field so we can synchronize access on it:
private List<String> mList = new ArrayList<>(); //initialize the field
Synchronize the modification operation (add). Do not read the data from the cursor inside the synchronization block because if its a low latency operation, the mList could not be read during that operation, blocking all other threads for quite a while.
//mList = new ArrayList<>(); remove that line in your code
String data = cursor.getString(cursor.getColumnIndex(DataProvider.NAME)); //do this before synchronized block!
synchronized(mList){
mList.add(data);
}
The read iteration must be inside the synchronization block, so no element gets added, while being iterated over:
synchronized(mList){
for (String name : mList) {
if (name.equals(query) {
return true;
}
}
}
So when two threads operate on the list, one thread can either add a single element or iterate over the entire list at a time. You have no parallel execution on these parts of the code.
Regarding the synchronized versions of a List (i.e. Vector, Collections.synchronizedList()). Those might be less performant because with synchronization you actually lose prallel execution as only one thread may run the protected blocks at a time. Further, they might still be prone to ConcurrentModificationException, which may even occur in a single thread. It is thrown, if the datastructure is modified between iterator creation and iterator should proceed. So those datastructures won't solve your problem.
I do not recommend manualy synchronization as well, because the risk of simply doing it wrong is too high (synchronizing on the wrong or different monitory, too large synchronization blocks, ...)
TL;DR
use a java.util.concurrent.CopyOnWriteArrayList
Use Collections.synchronizedList(new ArrayList<T>());
Ex:
Collections.synchronizedList(mList);
java synchronized block http://www.tutorialspoint.com/java/java_thread_synchronization.htm
class SomeClass {
private final Context mContext;
private List<String> mList = null;
SomeClass(Context context) {
mContext = context;
}
public void populateList() {
new Thread(new Runnable() {
#Override
public void run() {
synchronized(SomeClass.this){
mList = new ArrayList<>();
Cursor cursor = mContext.getContentResolver().query(
DataProvider.CONTENT_URI, null, null, null, null);
try {
while (cursor.moveToNext()) {
mList.add(cursor.getString(cursor.getColumnIndex(DataProvider.NAME)));
}
} catch (Exception e) {
Log.e("Error", e.getMessage(), e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
}).start();
}
public boolean searchList(String query) { // Invoked on the main thread
synchronized(SomeClass.this){
if (mList != null) {
for (String name : mList) {
if (name.equals(query) {
return true;
}
}
}
return false;
}
}
}
You could use a Vector which is the thread-safe equivalent of ArrayList.
EDIT: Thanks to Fildor's comment, I now know this doesn't avoid ConcurrentModificationException from being thrown using multiple threads:
Only single calls will be synchronized. So one add cannot be called while another thread is calling add, for example. But altering the list will cause the CME be thrown while iterating on another thread. You can read the docs of iterator on that topic.
Also interesting:
Why is Java Vector class considered obsolete or deprecated?
Vector vs Collections.synchronizedList(ArrayList)
Long story short: DO NOT use Vector.
Related
We have been looking at a threading error for a while and are not sure how this is possible. Below is a minimized example from our code. There is a cache holding data retrieved from a database (or: "a lengthy synchronous operation", as far as this example is concerned). There is a thread for reloading the cache, while other threads try to query the cache. There is a period of time when the cache is null, waiting to be reloaded. It should not be queryable during this time, and we tried to enforce this by synchronizing the methods that access the cache - both for reading and writing. Yet if you run this class for a while, you will get NPEs in search(). How is this possible?
Java docs state that "it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object".
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CacheMultithreading01 {
private long dt = 1000L;
public static void main(String[] args) {
CacheMultithreading01 cm = new CacheMultithreading01();
cm.demonstrateProblem();
}
void demonstrateProblem() {
QueryableCache cache = new QueryableCache();
runInLoop("Reload", new Runnable() {
#Override
public void run() {
cache.reload();
}
});
runInLoop("Search", new Runnable() {
#Override
public void run() {
cache.search(2);
}
});
// If the third "runInLoop" is commented out, no NPEs
runInLoop("_Clear", new Runnable() {
#Override
public void run() {
cache.clear();
}
});
}
void runInLoop(String threadName, Runnable r) {
new Thread(new Runnable() {
#Override
public synchronized void run() {
while (true) {
try {
r.run();
} catch (Exception e) {
log("Error");
e.printStackTrace();
}
}
}
}, threadName).start();
}
void log(String s) {
System.out.format("%d %s %s\n", System.currentTimeMillis(), Thread
.currentThread().getName(), s);
}
class QueryableCache {
private List<Integer> cache = new ArrayList<>();
public synchronized void reload() {
clear();
slowOp(); // simulate retrieval from database
cache = new ArrayList<>(Arrays.asList(1, 2, 3));
}
public synchronized void clear() {
cache = null;
}
public synchronized Integer search(Integer element) {
if (cache.contains(element))
return element;
else
return null;
}
private void slowOp() {
try {
Thread.sleep(dt);
} catch (InterruptedException e) {
}
}
}
}
//java.lang.NullPointerException
//at examples.multithreading.cache.CacheMultithreading01$QueryableCache.search(CacheMultithreading01.java:73)
//at examples.multithreading.cache.CacheMultithreading01$2.run(CacheMultithreading01.java:26)
//at examples.multithreading.cache.CacheMultithreading01$4.run(CacheMultithreading01.java:44)
//at java.lang.Thread.run(Thread.java:745)
We do not understand why the NPEs can happen even though the code is synchronized. We also do not understand why the NPEs stop happening if we comment out the third call to runInLoop (the one that does cache.clear).
We have also tried to implement locking using a ReentrantReadWriteLock - and the result is the same.
Since you don't have any more advanced locking, you can call clear() and search() consecutively. That will obviously cause a NPE.
Calling reload() and search() won't cause problems, since in reload the cache is cleared, then rebuilt, inside a synchronized block, preventing other (search) operations from being executed in between.
Why is there a clear() method that will leave cache in a "bad" state (which search() doesn't even check for)?
You have to check in the search method if cache is null. Otherwise calling contains on it in search can throw a NullPointerException in the case that you have previously set cache to null in the clear-method.
Synchronization is working as correctly.
The problem is that the method clear puts cache to null. And there is no guarantee that reload method will be called before search.
Also, note that the method reload, it's not releasing the lock. So, when you are waiting for the slowOp to finish, the other methods can't execute.
"There is a period of time when the cache is null, waiting to be reloaded."
This is your problem: clear sets things to null, and then returns, releasing the synchronization lock, allowing someone else to access.
It would be better to make the "new" assignment atomic and not clear().
Assuming that slowOp() needs to return data for the cache (private List<Integer> slowOp()) you retrieve that data before assigning it
ArrayList<Integer> waitingForData = slowOp();
cache = watingForData;
This 'updates' the cache only after the data is available. Assignment is an atomic operation, nothing can access cache while the reference is being updated.
Three different threads invoking clear() search() and reload() of the cache without a definitive interleaving. Since the interleaving doesn't gurantees the the sequence of lock being obtained for the clear() and search() threads there could be chances where the search thread is getting the lock over the object just after the clear() thread. In that case the search would result in the NullPointerException.
You may have to check for the cache equal to null in the search object and may be do a reload() from within the search() method. This would gurantee the search result or return null as applicable.
I know there are many questions asked on this but in my case i have it in a synchronised block and i am sure that nobody will be changing my array list.. But still i get this exception SOMETIMES if i am using for-each loop.. Why ?
Here is my code snippet
final static Object mLock = new Object();
private static ArrayList<ConnectionAndAuthCallback> mCallbacks;
private void callAuthCallbacks() {
synchronized (mLock) {
if (mCallbacks != null)
for (ConnectionAndAuthCallback calback : mCallbacks) { //here i get exception
calback.onAuthentication(mToken, calback.intent);
}
}
}
here is the code i do on Callback
#Override
public void onAuthentication(String token, Intent intent) {
web.loadUrl("xyz.com");
//unregister so that we wong get any exception or some more callbacks
SameClass.unRegisterAuthCallbacks(this);
}
and in Unregister function
public static void unRegisterAuthCallbacks(ConnectionAndAuthCallback callback) {
synchronized (mLock) {
if (mCallbacks != null)
if (mCallbacks.contains(callback)) {
mCallbacks.remove(callback); // This causing problem ?? In same thread "syncronised" wont work ??
}
}
}
You can't perform modifications on an ArrayList or remove() in this case that you are currently reading out of or looping through. Use iterators instead.
Check out this link.
And this link.
Answer was, In the same thread synchronised(){} wont work.
Even if you think it works then there might be a dead lock.
In my case i was removing callback object from ArrayList in the same thread where i called callback.
I am sorting my list data after every modification but since several threads could call the sorting method block, I decided to put it in a synchronized block. My code is as shown below. Problem is, despute the synchronized block, I am still getting 'ConcurrentModificationExceptio' on the line Collections.sort(storageBckupData.get(msg.what).getTotalItems(),new BackupDataComparator());. Any reason why I keep getting this?
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
default:
synchronized(LOCK) {
while(inUse) {
try {
LOCK.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
inUse = true;
Collections.sort(storageBckupData.get(msg.what).getTotalItems(),new BackupDataComparator());
inUse = false;
LOCK.notifyAll();
}
notifyDataSetChanged();
super.handleMessage(msg);
}
}
}
ConcurrentModificationException is not about whether you have synchronized or not, its when the collection detects a modification being done concurrently with something that does not allow it. For example you might have (somewhere else in your code which you are not showing) an iterator going through the list of items. Its about protecting the integrity of the collection.
What is happening in the other thread? Is it going through the list in parallel?
Draw a Sequence Diagram of both threads and you should clearly find what one thread is doing in parallel of the other.
Also, do you actually need to do that locking? You can get a synchronized collection through methods such as Collections.synchronizedList()
Why don't you use an appropriate data structure that takes care of sorting more efficiently? If each item is unique you could use a SortedSet implementation such as TreeSet.
Regrettably there is no way to specify a timeout when using a regular expression on a String in Java. So if you have no strict control over what patterns get applied to which input, you might end up having threads that consume a lot of CPU while endlessly trying to match (not so well designed) patterns to (malicious?) input.
I'm aware of the reasons why Thread#stop() is deprecated (see http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html). They are centered around objects that might get damaged in case of ThreadDeath exceptions, and which then pollute your running JVM environment and can lead to subtle errors.
My question to anyone who has deeper insight than me into the workings of the JVM is this: If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?
I created a rather defensive solution to be able to process regular expression matching with a timeout. I would be glad for any comment or remark, especially on problems that this approach can cause despite my efforts to avoid them.
Thanks!
import java.util.concurrent.Callable;
public class SafeRegularExpressionMatcher {
// demonstrates behavior for regular expression running into catastrophic backtracking for given input
public static void main(String[] args) {
SafeRegularExpressionMatcher matcher = new SafeRegularExpressionMatcher(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "(x+x+)+y", 2000);
System.out.println(matcher.matches());
}
final String stringToMatch;
final String regularExpression;
final int timeoutMillis;
public SafeRegularExpressionMatcher(String stringToMatch, String regularExpression, int timeoutMillis) {
this.stringToMatch = stringToMatch;
this.regularExpression = regularExpression;
this.timeoutMillis = timeoutMillis;
}
public Boolean matches() {
CallableThread<Boolean> thread = createSafeRegularExpressionMatchingThread();
Boolean result = tryToGetResultFromThreadWithTimeout(thread);
return result;
}
private CallableThread<Boolean> createSafeRegularExpressionMatchingThread() {
final String stringToMatchForUseInThread = new String(stringToMatch);
final String regularExpressionForUseInThread = new String(regularExpression);
Callable<Boolean> callable = createRegularExpressionMatchingCallable(stringToMatchForUseInThread,
regularExpressionForUseInThread);
CallableThread<Boolean> thread = new CallableThread<Boolean>(callable);
return thread;
}
private Callable<Boolean> createRegularExpressionMatchingCallable(final String stringToMatchForUseInThread,
final String regularExpressionForUseInThread) {
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return Boolean.valueOf(stringToMatchForUseInThread.matches(regularExpressionForUseInThread));
}
};
return callable;
}
private Boolean tryToGetResultFromThreadWithTimeout(CallableThread<Boolean> thread) {
startThreadAndApplyTimeout(thread);
Boolean result = processThreadResult(thread);
return result;
}
private void startThreadAndApplyTimeout(CallableThread<Boolean> thread) {
thread.start();
try {
thread.join(timeoutMillis);
} catch (InterruptedException e) {
throwRuntimeException("Interrupt", e);
}
}
private Boolean processThreadResult(CallableThread<Boolean> thread) {
Boolean result = null;
if (thread.isAlive()) {
killThread(thread); // do not use anything from the thread anymore, objects may be damaged!
throwRuntimeException("Timeout", null);
} else {
Exception exceptionOccurredInThread = thread.getException();
if (exceptionOccurredInThread != null) {
throwRuntimeException("Exception", exceptionOccurredInThread);
} else {
result = thread.getResult();
}
}
return result;
}
private void throwRuntimeException(String situation, Exception e) {
throw new RuntimeException(situation + " occured while applying pattern /" + regularExpression + "/ to input '"
+ stringToMatch + " after " + timeoutMillis + "ms!", e);
}
/**
* This method uses {#link Thread#stop()} to kill a thread that is running wild. Although it is acknowledged that
* {#link Thread#stop()} is inherently unsafe, the assumption is that the thread to kill does not hold any monitors on or
* even references to objects referenced by the rest of the JVM, so it is acceptable to do this.
*
* After calling this method nothing from the thread should be used anymore!
*
* #param thread Thread to stop
*/
#SuppressWarnings("deprecation")
private static void killThread(CallableThread<Boolean> thread) {
thread.stop();
}
private static class CallableThread<V> extends Thread {
private final Callable<V> callable;
private V result = null;
private Exception exception = null;
public CallableThread(Callable<V> callable) {
this.callable = callable;
}
#Override
public void run() {
try {
V result = compute();
setResult(result);
} catch (Exception e) {
exception = e;
} catch (ThreadDeath e) {
cleanup();
}
}
private V compute() throws Exception {
return callable.call();
}
private synchronized void cleanup() {
result = null;
}
private synchronized void setResult(V result) {
this.result = result;
}
public synchronized V getResult() {
return result;
}
public synchronized Exception getException() {
return exception;
}
}
}
EDIT:
Thanks to dawce who pointed me to this solution I have been able to solve my original problem without the need for additional threads. I have posted the code there. Thanks to all who have responded.
You can use Thread.stop() if you determine its the only solution available to you. You may need to shutdown and restart your applicaton to ensure its in a good state.
Note: a Thread can capture and ignore ThreadDeath so stop isn't guarenteed to stop all threads.
An alternative way to stop a thread is to run it in a different process. This can be killed as required. This can still leave resources in an incosistent state (like lock files) but it is less likely and easier to control.
The best solution of course is to fix the code so it doesn't do this in the first place and respects Thread.interrupt() instead.
Instead of using Thread.stop() which is deprecated, use Thread.interrupt() which will stop raise the interrupt flag which can be checked via isInterrupted() or interrupted(), or throws an InterruptedException.
My pattern for building extending the Thread class is like this
class MyThread extends Thread{
private volatile boolean keepRunning = true;
public void run(){
while(keepRunning){
// do my work
}
}
public void killThread(){
keepRunning = false;
this.interrupt();
}
}
I'm not saying my way of handling it is perfect, there may bet better, but this works for me.
If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?
It is up to you to decide if it is "acceptable". All we can do is to advise on whether it is safe. And the answer is that it isn't.
what about the non-obvious monitors and references that it holds?
what about notifies, etc that it would otherwise make?
what about actions that it might otherwise make affecting statics?
The problem is that it is difficult (in most cases) to know for sure that you've considered all of the possible interactions that the thread might have with the rest of the application.
Restarting the application is exactly what I try to avoid ...
It strikes me that that is the real root of your problem; i.e. you've designed a program without taking account of the fact that long-running programs need to be restarted for pragmatic reasons. Especially complicated ones that have potential bugs.
If you specifically design your thread code to not hold locks etc., (yes, and this includes the non-explicit locks. eg. a malloc lock that may be used when changing string sizes), then stop the thread, yes. Polling an 'interrupted' flag is fine, except that it means polling an 'interrupted' flag, ie. overhead during the 99.9999% of the time it is not actually set. This can be an issue with high-performance, tight loops.
If the check can be kept out of an innermost loop and still be checked reasonably frequently, then that is indeed the best way to go.
If the flag cannot be checked often, (eg. because of a tight loop in inaccessible library code), you could set the thread priority to the lowest possible and forget it until it does eventually die.
Another bodge that is occasionally possible is to destroy the data upon which the thread is working in such a way that the library code does exit normally, causes an exception to be raised and so control bubbles out of the opaque library code or causes an 'OnError' handler to be called. If the lib. is operating on a string, splatting the string with nulls is sure to do something. Any exception will do - if you can arrange for an AV/segfault in the thread, then fine, as long as you get control back.
I have a class proposing translations utilities. The translations themselves should be reloaded every 30 minutes. I use Spring Timer support for that. Basically, my class looks like :
public interface Translator {
public void loadTranslations();
public String getTranslation(String key);
}
loadTranslations() can be pretty long to run, so while it is running the old translations are still available. This is done by loading the translations in a local Map and just changing the reference when all translations are loaded.
My problem is : how do I make sure that when a thread is already loading translations, is a second one also tries to run, it detects that and returns immediately, without starting a second update.
A synchronized method will only queue the loads ... I'm still on Java 1.4, so no java.util.concurrent.
Thanks for your help !
Use some form of locking mechanism to only perform the task if it is not already in progress. Acquiring the locking token must be a one-step process. See:
/**
* #author McDowell
*/
public abstract class NonconcurrentTask implements Runnable {
private boolean token = true;
private synchronized boolean acquire() {
boolean ret = token;
token = false;
return ret;
}
private synchronized void release() {
token = true;
}
public final void run() {
if (acquire()) {
try {
doTask();
} finally {
release();
}
}
}
protected abstract void doTask();
}
Test code that will throw an exception if the task runs concurrently:
public class Test {
public static void main(String[] args) {
final NonconcurrentTask shared = new NonconcurrentTask() {
private boolean working = false;
protected void doTask() {
System.out.println("Working: "
+ Thread.currentThread().getName());
if (working) {
throw new IllegalStateException();
}
working = true;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!working) {
throw new IllegalStateException();
}
working = false;
}
};
Runnable taskWrapper = new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
shared.run();
}
}
};
for (int i = 0; i < 100; i++) {
new Thread(taskWrapper).start();
}
}
}
I am from a .net background(no java experience at all), but you could try a simple static flag of some sort that checks at the beginning of the method if its alrady running. Then all you need to do is make sure any read/write of that flag is synchronized. So at beginning check the flag, if its not set, set it, if it is set, return. If its not set, run the rest of the method, and after its complete, unset it. Just make sure to put the code in a try/finally and the flag iunsetting in the finally so it always gets unset in case of error. Very simplified but may be all you need.
Edit: This actually probably works better than synchronizing the method. Because do you really need a new translation immediately after the one before it finishes? And you may not want to lock up a thread for too long if it has to wait a while.
Keep a handle on the load thread to see if it's running?
Or can't you just use a synchronized flag to indicate if a load is in progress?
This is actually identical to the code that is required to manage the construction of a Singleton (gasp!) when done the classical way:
if (instance == null) {
synchronized {
if (instance == null) {
instance = new SomeClass();
}
}
}
The inner test is identical to the outer test. The outer test is so that we dont routinely enter a synchronised block, the inner test is to confirm that the situation has not changed since we last made the test (the thread could have been preempted before entering Synchronized).
In your case:
if (translationsNeedLoading()) {
synchronized {
if (translationsNeedLoading()) {
loadTranslations();
}
}
}
UPDATE: This way of constructing a singleton will not work reliably under your JDK1.4. For explanation see here. However I think you are you will be OK in this scenario.