I was reading about Immutable objects in java.
There is a statement which states - "Immutable objects are thread-safe".
I need more clarification for the above statement:
If I have a shared resource of type 'String' which is shared with multiple threads (say 3)
And if one of the thread make changes to the shared reference, it will create a new String object and that will available only with that Thread object and other threads will not get to know about the changes made by one of the thread.
Will it not lead to data inconsistency?
So could anyone please help me understand this?
Thanks in advance.
An object of an immutable class is always thread-safe. However, the reference to such an object doesn't have anything to do with that. It might be or it might not be thread-safe, depending on how the class that contains the reference to this thread-safe object (a String object, for example) and the methods to manipulate such a reference.
See this example below, to illustrate the explanation:
public class User {
private string name;
public User(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
}
So, even though String is an immutable and thread-safe class, the reference to it in the class User above isn't thread-safe because its methods could be concurrently changing this reference to new String objects.
If you wanted it to be thread-safe, there would be many options. One of them would be to set all methods that can change the name object as synchronized.
Immutable types (in any language) are special reference types.
Their uniqueness lies in the fact that when they are changed they are replaced with an entirely new instance which reflects the previous state + the change
Lets say 2 threads running a function which receive an immutable reference type object as a parameter ( and of course i'll use string for this example)
// pseudo code !!
main()
{
var str = "initialState";
new Thread(Do,str,1).Start();
new Thread(Do,str,2).Start();
}
void Do(string arg,int tid)
{
int i = 0;
while(true)
{
arg += "running in thread " + tid + "for the " + i + "time";
Console.WriteLine(arg);
}
}
This program while print in parallel the number of occurrences running in each thread with out effecting what was printed in the other thread.
Why ?
If you think about it string is a reference type, it is passed by reference and not by value, meaning it is not copied only a copy of the reference occurs.
And yet though it was initially the same object. after the first change it is no longer and a different one is created.
If it was still the same object after changes it would be a shared resource between the 2 threads and will disrupt the state those threads men't to print.
Related
Lets say I have a code like this in my servlet:
private static final String RESOURCE_URL_PATTERN = "resourceUrlPattern";
private static final String PARAM_SEPARATOR = "|";
private List<String> resourcePatterns;
#Override
public void init() throws ServletException {
String resourcePatterns = getInitParameter(RESOURCE_URL_PATTERN);
this.resourcePatterns = com.google.common.base.Splitter.on(PARAM_SEPARATOR).trimResults().splitToList(resourcePatterns);
}
Is this thread safe to use 'resourcePatterns' if it will never be modified?
Lets say like this:
private boolean isValidRequest(String servletPath) {
for (String resourcePattern : resourcePatterns) {
if (servletPath.matches(resourcePattern)) {
return true;
}
}
return false;
}
Should I use CopyOnWriteArrayList or ArrayList is OK in this case?
Yes, List is fine to read from multiple threads concurrently, so long as nothing's writing.
For more detailed information on this, please see this answer that explains this further. There are some important gotchas.
From java concurrency in practice we have:
To publish an object safely, both the reference to the object and the
object's state must be made visible to other threads at the same time.
A properly constructed object can be safely published by:
Initializing an object reference from a static initializer. Storing a
reference to it into a volatile field. Storing a reference to it into
a final field. Storing a reference to it into a field that is properly
guarded by a (synchronized) lock.
your list is neither of these. I suggest making it final as this will make your object effectively immutable which in this case would be enough. If init() is called several times you should make it volatile instead. With this I of course assume that NO changes to the element of the list occur and that you don't expose any elements of the list either (as in a getElementAtPosition(int pos) method or the like.
java.lang.String is only effectively immutable. Brian Goetz of "Java Concurrency in Practice" said something like effectively immutable objects will only be thread safe if safely published. Now, say I unsafely publish String like this:
public class MultiThreadingClass {
private String myPath ="c:\\somepath";
//beginmt runs simultaneously on a single instance of MultiThreading class
public void beginmt(){
Holder h = new Holder();
h.setPath(new File(myPath)); //line 6
h.begin();
}
}
public class Holder {
private File path;
public void setPath(File path){
this.path = path;
}
public void begin(){
System.out.println(path.getCanonicalPath()+"some string");
}
}
At the moment that the MultiThreadingClass is initializing with its constructor, it could happen that the File constructor on line 6 may not see the value of myPath.
Then, about three seconds after the construction of the unsafely published String object, threads on MultiThreadingClass are still running. Could there still be a chance that the File constructor may not see the value of myPath?
Your statement that you are asking your question about:
At the moment that the MultiThreadingClass is initializing with its
constructor, it could happen that the File constructor on line 6 may
not see the value of myPath.
The answer is complicated.
You don't need to worry about the char-array value inside the String object. As I mentioned in the comments, because it is a final field that is assigned in the constructors, and because String doesn't pass a reference to itself before assigning the final field, it is always safely published. You don't need to worry about the hash and hash32 fields either. They're not safely published, but they can only have the value 0 or the valid hash code. If they're still 0, the method String.hashCode will recalculate the value - it only leads to other threads recalculating the hashCode when this was already done earlier in a different thread.
The reference myPath in MultiThreadingClass is not safely published, because it is not final. "At the moment that the MultiThreadingClass is initializing with its constructor", but also later, after the constructor completed, other Threads than the thread that ran the constructor may see the value null in myPath rather than a reference to your string.
There's an example in the Java Memory Model section of the Java Language Specification [version 8 linked but this is unchanged since JMM was released in JSR-133]:
Example 17.5-1. final Fields In The Java Memory Model
The program below illustrates how final fields compare to normal fields.
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
}
The class FinalFieldExample has a final int field x and a non-final
int field y. One thread might execute the method writer and another
might execute the method reader.
Because the writer method writes f after the object's constructor
finishes, the reader method will be guaranteed to see the properly
initialized value for f.x: it will read the value 3. However, f.y is
not final; the reader method is therefore not guaranteed to see the
value 4 for it.
This is even likely to happen on a heavily loaded machine with many threads.
Workarounds/solutions:
Make myPath a final field (and don't add constructors that pass out the this reference before assigning the field)
Make myPath a volatile field
Make sure that all threads accessing myPath synchronize on the same monitor object before accessing myPath. For example, by making beginmt a synchronized method, or by any other means.
Could there still be a chance that the File constructor may not see the value of myPath?
Answer is yes it is possible since Java Memory Model guarantees visibility of only final fields
:-
"A new guarantee of initialization safety should be provided. If an object is properly constructed (which means that references to it do not escape during construction), then all threads which see a reference to that object will also see the values for its final fields that were set in the constructor, without the need for synchronization."
JSR 133 Link
However I feel this situation is impossible to recreate (I too had tried earlier a similar theory but ended in vain).
There is a case of unsafe publication/escape of this reference within the constructor which can lead to the scenario of myPath not being initialized properly. An example for this is given in Listing 3.7 of the book you mentioned. Below is an example of making your class this reference to escape in constructor.
public class MultiThreadingClass implements Runnable{
public static volatile MultiThreadingClass unsafeObject;
private String myPath ="c:\\somepath";
public MultiThreadingClass() {
unsafeObject = this;
.....
}
public void beginmt(){
Holder h = new Holder();
h.setPath(new File(myPath)); //line 6
h.begin();
}
}
The above class can cause other threads to access unsafeObject reference even before the myPath is correctly set but again recreating this scenario might be difficult.
I was reading book "java concurrency in practice" and end up with some doubts after few pages.
1) Voltile with non premitive data types :
private volatile Student s;
what is significance of volatile when it comes with non premitive data types ? (I think in this case only think that is sure to be visible to all threads is what Strudent object s is pointing currently and it is possible one thread A modifies some internal member of student and that is not visible to other threads. Am I right ??)
2)
Is a variable can be immutable , even if internal members are not declared as final ??
For example :
Class A {
private Set<String> s = new Set();
public A() {
s.add("Moe");
s.add("Larry");
s.add("Curly");
}
}
In this class do we need to make Set s final to make it immutable or this class is still immutable ? (because even in this case we can't change state of object after it is created).
3 ) There is one example in book that shows how to use volatile and immutable class in combination to get synchronization. Before I put that question I have one more doubt.
suppose there is some function like this :
private Student s = new Student;
void func() {
s.func2(); // 1
if(s.isPossible()) { //2
s = new Student(); //3
}
}
a)func2() acess internal members of s. Now consider Thread A entered into func2 after executing line 1 and Thread B same time reassign s with new object. When Thread A resumes
what it will use new object or the old one ? ( suppose s initally points to memory location 100 (old object) and after a new object is assigned it started pointing to 200 (new object)
then when Thread A resumes it will acess address 100 or address 200).
b) If I make s volatile , will it make any difference to above case.
4.) And here is last one
#Immutable
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;
public OneValueCache(BigInteger i,
BigInteger[] factors) {
lastNumber = i;
lastFactors = Arrays.copyOf(factors, factors.length);
}
public BigInteger[] getFactors(BigInteger i) {
if (lastNumber == null || !lastNumber.equals(i))
return null;
else
return Arrays.copyOf(lastFactors, lastFactors.length);
}
}
#ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache = new OneValueCache(null, null);
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i); // Position A
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors); // Position B
}
encodeIntoResponse(resp, factors);
}
}
Accroding to book class "VolatileCachedFactorizer" is thread safe. Here is my reasoning why it is thread safe (Correct me if I am wrong.) Positin A and Position B are
doubtful positions.
Position A : As cache is pointing to immutable object , any function call is safe (right ?).
Position B : It can have two issue
a)Threads see cache improperly initialized . Not possible in this case as immutable object are guaranteed to be properly initialized (right ?).
b)New assigned object not visible to other threads. Not possible is this case as cache is volatile (right ?).
But it is possible thread A call getFactors() and other thread B reassign cache , in this case A will continue to see old object (right ?)
Yes; volatile only applies to the reference it's applied to.
No; objects that happen to be pointed to by final fields do not magically become immutable.
An object with mutable non-public members is only immutable if those members can never be mutated. (obviously)
Found out after some testing all my answers.
volatile only applies to reference. Any object point by volatile object need not to be visible other threads.
Yes final is important. Without it object of class will not be immutable.
Suppose a variable "obj" is pointing to location x(where the actual object is placed) when a function call on obj is started then during function call all member variables will be read from location x even if some other thread assign a different object on "obj".
Assumed explanations for all answers are correct.
In this piece of code i pass a name into a method that modifies the String literal name but not the object itself, when the code exits the method, the object (as identified by the hashcode) is the same, however not the name that is modified in the method.
How should i explain this?
public class ObjectContentsPassByReferenceApp {
private static void modifyObject(Bus bus) {
bus.setName("SBS Transit");
}
public static void main(String args[]) {
Bus bus;
bus = new Bus();
bus.setName("Trans Island Bus");
System.out.println("Bus initially set to (hashcode): " + bus);
System.out.println("Bus name: " + bus.getName());
modifyObject(bus);
System.out.println("After calling modifyObject (hashcode): " + bus);
System.out.println("Bus name: " + bus.getName());
}
}
class Bus {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Run results:
Bus initially set to (hashcode): sg.java.concepts.passByReference.Bus#8d2ed0
Bus name: Trans Island Bus
After calling modifyObject (hashcode): sg.java.concepts.passByReference.Bus#8d2ed0
Bus name: SBS Transit
You haven't overridden hashCode - therefore it will use the implementation in java.lang.Object, which doesn't vary over the course of an object's lifetime. You haven't overridden equals either... which means that a.equals(b) will only return true for Bus a and Bus b if a and b refer to the exact same object - rather than objects with equal name.
Note that the names in your code suggest that Java uses pass by reference. It doesn't - it always uses pass by value, but those values are always either primitives or references - never actual objects. The same is true for simple assignment etc.
In your code, you're creating a single Bus object. Think of it as a real life bus. It has a name painted on it, and a serial number embossed on it (the latter being the hash code). When you call the method, that's telling the method how to get to the Bus object - it's not creating a new Bus. The method comes and paints over the name with a new one, but that does nothing to the serial number, which is the same as it ever was.
Also note that name is not a string literal - it's a string variable. Its initial value comes from a string literal, but changing the value later does nothing to the original string object.
If you want the hashcode to depend on a variable (i.e. name) then you'll need to override the hashCode method. A simple example:
public class Bus {
private String name;
public int hashCode() {
return name.hashCode();
}
}
The hashCode implementation in java.lang.Object does not use any kind of reflection to look up variables, so you almost always need to override hashCode.
Note that you should always override equals if you override hashCode and vice versa.
There are a bunch of useful tools for helping you implement hashCode. Check out Apache Commons lang and take a look at their HashCodeBuilder class.
Say you have the following class
public class AccessStatistics {
private final int noPages, noErrors;
public AccessStatistics(int noPages, int noErrors) {
this.noPages = noPages;
this.noErrors = noErrors;
}
public int getNoPages() { return noPages; }
public int getNoErrors() { return noErrors; }
}
and you execute the following code
private AtomicReference<AccessStatistics> stats =
new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));
public void incrementPageCount(boolean wasError) {
AccessStatistics prev, newValue;
do {
prev = stats.get();
int noPages = prev.getNoPages() + 1;
int noErrors = prev.getNoErrors;
if (wasError) {
noErrors++;
}
newValue = new AccessStatistics(noPages, noErrors);
} while (!stats.compareAndSet(prev, newValue));
}
In the last line while (!stats.compareAndSet(prev, newValue)) how does the compareAndSet method determine equality between prev and newValue? Is the AccessStatistics class required to implement an equals() method? If not, why? The javadoc states the following for AtomicReference.compareAndSet
Atomically sets the value to the given updated value if the current value == the expected value.
... but this assertion seems very general and the tutorials i've read on AtomicReference never suggest implementing an equals() for a class wrapped in an AtomicReference.
If classes wrapped in AtomicReference are required to implement equals() then for objects more complex than AccessStatistics I'm thinking it may be faster to synchronize methods that update the object and not use AtomicReference.
It compares the refrerences exactly as if you had used the == operator. That means that the references must be pointing to the same instance. Object.equals() is not used.
Actually, it does not compare prev and newValue!
Instead it compares the value stored within stats to prev and only when those are the same, it updates the value stored within stats to newValue. As said above it uses the equals operator (==) to do so. This means that anly when prev is pointing to the same object as is stored in stats will stats be updated.
It simply checks the object reference equality (aka ==), so if object reference held by AtomicReference had changed after you got the reference, it won't change the reference, so you'll have to start over.
Following are some of the source code of AtomicReference. AtomicReference refers to an object reference. This reference is a volatile member variable in the AtomicReference instance as below.
private volatile V value;
get() simply returns the latest value of the variable (as volatiles do in a "happens before" manner).
public final V get()
Following is the most important method of AtomicReference.
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
The compareAndSet(expect,update) method calls the compareAndSwapObject() method of the unsafe class of Java. This method call of unsafe invokes the native call, which invokes a single instruction to the processor. "expect" and "update" each reference an object.
If and only if the AtomicReference instance member variable "value" refers to the same object is referred to by "expect", "update" is assigned to this instance variable now, and "true" is returned. Or else, false is returned. The whole thing is done atomically. No other thread can intercept in between. As this is a single processor operation (magic of modern computer architecture), it's often faster than using a synchronized block. But remember that when multiple variables need to be updated atomically, AtomicReference won't help.
I would like to add a full fledged running code, which can be run in eclipse. It would clear many confusion. Here 22 users (MyTh threads) are trying to book 20 seats. Following is the code snippet followed by the full code.
Code snippet where 22 users are trying to book 20 seats.
for (int i = 0; i < 20; i++) {// 20 seats
seats.add(new AtomicReference<Integer>());
}
Thread[] ths = new Thread[22];// 22 users
for (int i = 0; i < ths.length; i++) {
ths[i] = new MyTh(seats, i);
ths[i].start();
}
Following is the github link for those who wants to see the running full code which is small and concise.
https://github.com/sankar4git/atomicReference/blob/master/Solution.java