I have a method (example below) which creates a new list, puts some stuff into it, and passes it along to another thread to operate on.
This seems thread safe. The list is local to the method which creates it. The method operates on the list and doesn't pass it to another thread until it is done operating on it.
But this feels wrong, because the list is accessed in two separate threads but it is not synchronized.
Is this acceptable thread-safe code?
class App
{
public static void main(String[] args)
{
final ArrayList<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(5);
final ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(new Runnable() {
@Override public void run()
{
for (Integer i : list)
System.out.println(i);
}});
es.shutdown();
}
}
If an object created locally never escapes the method it was created in, it is thread-safe. In fact, you can also pass it on to other methods and objects as long as none of these methods or objects make the passed object available to other threads.
Using Atomic Variable Using an atomic variable is another way to achieve thread-safety in java. When variables are shared by multiple threads, the atomic variable ensures that threads don't crash into each other.
Local variables are stored in each thread's own stack. That means that local variables are never shared between threads. That also means that all local primitive variables are thread safe.
The local variables of a function are unique to each thread that runs the function. However, the static and global variables are shared by all threads in the process. With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index.
It's safe because one thread writes to the list, then one other thread reads from the list, and the executor service guarantees a happen-before relationship when you submit a task.
Quote from the documentation:
The methods of all classes in java.util.concurrent and its subpackages extend these guarantees to higher-level synchronization. In particular:
[...]
Actions in a thread prior to the submission of a Runnable to an Executor happen-before its execution begins. Similarly for Callables submitted to an ExecutorService.
This is thread-safe, yes because this main
is creating this thread because it is constructing the executor which starts the underlying thread and because it goes through a BlockingQueue
which is synchronized.
What you need to be careful of is:
Passing a list off to a thread inside of an object constructor since the JIT is able to optimize field initialization outside the constructor.
Passing the list to another thread without synchronization. For example if one thread initializes the list and then sets it on a local field which is accessible from another thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With