问题
I am creating a Runnable in the following way:
public class AbcRunnable implements Runnable
{
Qwe qwe;
Rst rst;
public void run() {
// some operations on qwe and rst which are changing their value
}
}
public class AbcThreadPool {
private final AbcThreadPoolExecutor executor;
public InventoryAvailabilityThreadPool(final AbcRunnableFactory factory,
final Integer poolSize) {
executor = new AbcThreadPoolExecutor(factory, poolSize);
for (int i = 0; i < poolSize; ++i) {
executor.execute(factory.get());
}
}
private static class AbcThreadPoolExecutor extends ThreadPoolExecutor {
private final AbcRunnableFactory factory;
public AbcThreadPoolExecutor(final AbcRunnableFactory factory,
final int poolSize) {
super(poolSize, poolSize, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
this.factory = factory;
allowCoreThreadTimeOut(false);
}
}
}
public class AbcRunnableFactory {
@Override
public AbcRunnable get() {
return new AbcRunnable();
}
}
Initialization of Qwe and Rst is being done by the guice module, say, as follows:
@Provides
@Singleton
private AbcRunnableFactory provideAbcRunnableFactory() {
return new AbcRunnableFactory(
new Qwe(), new Rst());
}
So, here AbcRunnable has 2 variables: qwe and rst. My question here is, do different Runnables have their own variables or are they getting shared? Please help in explaining this.
I am very confused when trying to understand what is thread safe or not. So, this may be a very naive question.
回答1:
Each new instance of AbcRunnable
will have its own set of fields (list1
and map1
). Since your loop is calling factory.get()
in each iteration, and that creates a new AbcRunnable
, each thread pool task will have a unique instance of the runnable and its contained fields.
Now, you haven't showed how you initialize the fields inside AbcRunnable
:
- If you create new
List
andMap
instances in the constructor, then nothing is shared between threads and your code is thread-safe. - If you are passing in any of these values from the outside, then your different
AbcRunnable
instances could potentially share references to the same list/map and you will need to ensure synchronized access to the data (or use a concurrent collection implementation, which is already thread-safe).
回答2:
The answer depends how you instantiate your runables. There is a lot going on here so let's simplify. Say we have a very large set of n numbers we want to sum. We can split the set in two and create 2 threads, when they return we just sum the two results. Because we could divide the set in two and sum at the end there is nothing shared, everything is thread safe.
Now let's say we want to know how many of our n numbers have been summed as they are working. We need a shared counter that each thread can increment as the two threads sum. So if the counter is 100 and both threads try to increment it at the same time, both threads will read 100 add 1 and return 101 to memory, the new count will be 101 but really 102 numbers have been summed. For shared variables like our counter we need to make sure only one thread at a time has access at a time if they are writing to it.
In your case if you send the same list or map to two threads you would have a problem because lists and maps are passed by reference or the address in memory is what is sent to the new thread so both might try to modify them at the same time. However, if you split your list and map into distinct values before sending it then you should be fine.
来源:https://stackoverflow.com/questions/55979106/does-runnable-share-the-data-structure-if-they-are-getting-changed