Is String s = "foobar" atomic? - java

Is String s = "foobar"; atomic?
Assigning a object-reference should be, but I'm no really sure.
Thanks.

Yes. All reference assignments are atomic in java.
Just note that a composite statement like String s = new String("foobar") is not atomic, because it comprises of an object creation and then an assignment separately.
Also note that "assignments to long and double variables may not be atomic", from JLS-17.7

Many great answers have already been give here. Still I want something more "official" about claims like "All reference assignments are atomic in java", and why String s = "foobar" does not create a new object at runtime. Here is what is written in Java Language Spec. (Abbr. JLS).
Below are some examples:
String str1 = "foo"; // line 1, atomic
String str2 = "foo" + "bar"; // line 2, atomic
String str3 = str1; // line 3, atomic
String str4 = str1 + str2; // line 4, not atomic
String str5 = new String("foobar"); // line 5, not atomic
Line 1 and line 2 are atomic because:
They are both constant expressions, and are computed at compile time. There are no object construction occurred at runtime.
JLS - 15.28: A constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using ... literals of primitive type and literals of type String.
JSL - 3.10.5: Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
Writes to and reads of references are always atomic.
JLS - 17.7: Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
Line 3 is atomic because:
There is only a reference assignment in this line.
JLS - 17.7
Line 4 is not atomic because:
By concat two string variables, a new String object is created at runtime. Object construction is not atomic.
JLS - 15.8.1 - String Concatenation Operator +: The String object is newly created (§12.5) unless the expression is a constant expression (§15.28).
JLS - 3.10.5 - String literals: Strings computed by concatenation at run time are newly created and therefore distinct.
Line 5 is not atomic because:
A String object is constructed at runtime in this line.

Yes, but if you're worried about race conditions, you should at least be aware of 'synchronized' methods/blocks.
And note that this is not atomic because it contains two operations:
String s = string_a + string_b;

Related

In Java, when we print a string literal on to the terminal, does this string literal also be stored in the string pool?

I am aware that when we initialize a string literal to a variable this literal will be stored in the string pool by the JVM. Consider the piece of code below.
System.out.println("This is a string literal");
Does the string literal within the quotes also be stored in the string pool even if I don't initialize it to a variable?
I will preface this answer by saying that there is little practical use in gaining a deep understanding of the Java string pool. From a practical perspective, you just need to remember two things:
Don't use == to compare strings. Use equals, compareTo, or equivalent methods.
Don't use explicit String.intern calls in your code. If you want to avoid potential problems with duplicate strings, enable the string de-duplication feature that is available in modern Java GCs.
I am aware that when we initialize a string literal either using the 'new' keyword or not, this literal will be stored in the string pool by the JVM.
This is garbled.
Firstly, you don't "initialize" a string literal. You initialize a variable.
String hi = "hello"; // This initializes the variable `hi`.
Secondly you typically don't / shouldn't use a string literal with new.
String hi = new String("hello"); // This is bad. You should write this as above.
The normal use-case for creating a string using new is something like this:
String hi = new String(arrayOfCharacters, offset, count);
In fact, creation and interning of the String object that corresponds to a string literal, happens either at the first time that the literal is used in an expression or at an earlier time. The precise details (i.e. when it happens) are unspecified and (I understand) version dependent.
The first usage might be in a variable initialization, or it might be in something else; e.g. a method call.
So to your question:
Consider the piece of code below:
System.out.println("This is a string literal");
Does the string literal within the quotes also be stored in the string pool even if I do not initialize it?
Yes, it does. If that was the first time the literal was used, the code above may be the trigger for this to happen. But it could have happened previously; e.g. if the above code was run earlier.
As a followup, you asked:
Why does the String Pool collect string literals which are not stored in a variable and just displayed in the console?
Because the JLS 3.10.5 requires that the String objects which correspond to string literals are interned:
"Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern (§12.5)."
And you asked:
The Presence of the String Pool help optimize the program. By storing literals as such (which is actually not required because it is just to be displayed in the console), isn't it the case that it goes against its whole purpose (which is optimization)?
The original idea for interning and the string pool was to save memory. That made sense 25 years ago when the Java language was designed and originally specified. These days even a low-end Android phone has 1GB of RAM, and interning of string literals to save a few thousand bytes is kind of pointless. Except that the JLS says that this must happen.
But the answer is No, it doesn't go against the (original) purpose. This statement:
System.out.println("This is a string literal");
could be executed many times. You don't want / need to create a new String object for the literal each time that you execute it. The thing is that the JVM doesn't know what is going to happen.
Anyway, the interning must happen because that is what the spec says.

Does string pool store literals or objects?

Stackoverflow is full of questions related to different types of String initialization. I understand how different is String s = "word" to String s = new String("word"). So no need to 'touch' that topic.
I noticed that different people refer that String pool stores constants/objects/literals.
Constants are understandable, as they are final, so they always 'stay' there. Yes, also duplicates aren't stored in SCP.
But I can't understand does SCP store objects or literals. They are totally different concepts. Object is an entity, while literal is just a value. So what is the correct answer to this. Does SCP store objects or literals? I know it can't be both :)
Literals are a chunk of source code that is delimited by ". For example, in the following line of source code:
String s = "Hello World";
"Hello World" is a string literal.
Objects are a useful abstraction for a meaningful bits of memory with data that (when grouped together) represents something, whether it be a Car, Person, or String.
The string pool stores String objects rather than String literals, simply because the string pool does not store source code.
You might hear people say "the string pool stores string literals". They (probably) don't mean that the string pool somehow has the source code "Hello World" in it. They (probably) mean that all the Strings represented by string literals in your source code will get put into the string pool. In fact, the Strings produced by constant expressions in your source code also gets added to the string pool automatically.
Strictly speaking, "literal" is not a value; It is a syntactic form. A String literal in Java is a double quote followed by some non-double-quote (or escaped double quote) characters, ending in another double quote. A "literal value" is a value that is created from a source-code literal, as opposed to an evaluated value such as a.concat(b). The core difference is that the literal value can be identified at compilation time, while an evaluated value can only be known during execution. This allows the compiler to store the literal values inside the compiled bytecode. (Since constants initialised by literal values are also known by the compiler at compile time, evaluations that only use constants can also be computed at compile time.)
In colloquial speech one can refer to a literal value as a "literal", but that may be the source of your confusion - a value is a value, whether its origin is a literal, or an evaluation.
I know it can't be both
The distinction between a literal value and an evaluated value is separate from a distinction between an object value and a primitive value. "foo" is a literal String value (and since Strings are objects, it is also an object). 3 is a literal primitive (integer) value. If x is currently 7, then 18 - x evaluates to a non-literal primitive value of 11. If y is currently "world!", then "Hello, " + y evaluates to a non-literal, non-primitive value "Hello, world!".
Nice question. The answer can be found through how String::intern() was implemented. From javadoc:
* When the intern method is invoked, if the pool already contains a
* string equal to this {#code String} object as determined by
* the {#link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {#code String} object is added to the
* pool and a reference to this {#code String} object is returned.
* <p>
So the String pool stores string object.
We can open the source code to confirm the answer. String::intern() is a native method and it's defined in StringTable::intern(), symbolTable.hpp
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
unsigned int hashValue = hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
oop found_string = the_table()->lookup(index, name, len, hashValue);
// Found
if (found_string != NULL) {
ensure_string_alive(found_string);
return found_string;
}
... ...
Handle string;
// try to reuse the string if possible
if (!string_or_null.is_null()) {
string = string_or_null;
} else {
string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
}
... ...
// Grab the StringTable_lock before getting the_table() because it could
// change at safepoint.
oop added_or_found;
{
MutexLocker ml(StringTable_lock, THREAD);
// Otherwise, add to symbol to table
added_or_found = the_table()->basic_add(index, string, name, len,
hashValue, CHECK_NULL);
}
ensure_string_alive(added_or_found);
return added_or_found;
}
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/f3108e56b502/src/share/vm/classfile/symbolTable.cpp

String concatenation: + operator with String literal

why s3==s4 returns false while s2==s3 returns true in line no. 8 and 7 respectively.
1. String s="hello";`
2. String s1="he"+"llo";
3. String s2="hello"+123;
4. String s3="hello123";
5. String s4=ss+"123";
7. System.out.println(s==s1);//prints true
8. System.out.println(s2==s3);//prints true
9. System.out.println(s3==s4);//prints false
s + "123"; is not compile-time evaluable so is not a candidate for string internment. (Note that if s was final then it would be.)
Therefore its reference will not be the same as s3, so the output is false.
The others all compare true due to string internment and the compile-time evaluabality of the expressions.
When you use == operator to check the equality of Strings, it checks if the location of the Strings in the memory is the same.
In cases 2 and 4, the Strings "hello" and "hello123" will already be in the String Constant Pool (due to lines 1 and 3) and will be recognized as equivalent to those Strings, and will use the same place in memory for each. In simple terms, it will create a String object and plug it into both instances of "hello" and "hello123".
When you do:
String s4=s+"123";
At run time, it creates a new memory location for s4, since, the JLS says that:
Strings computed by concatenation at run-time are newly created and therefore distinct.
So, the memory locations are different, and hence it gives false as the output.

== operator does not compare references for String [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
String comparison and String interning in Java
I understand how String equals() method works but was surprised by some results I had with the String == operator.
I would have expected == to compare references as it does for other objects.
However distinct String objects (with the same content) == returns true and furthermore even for a Static String object (with the same content) which is obviously not the same memory address.
I guess == has been defined the same as equals to prevent its misuse
No, == does just compare references. However, I suspect you've been fooled by compile-time constants being interned - so two literals end up refererring to the same string object. For example:
String x = "xyz";
String y = "xyz";
System.out.println(x == y); // Guaranteed to print true
StringBuilder builder = new StringBuilder();
String z = builder.append("x").append("yz").toString();
System.out.printn(x == z); // Will print false
From section 3.10.5 of the Java language specification:
String literals-or, more generally, strings that are the values of constant expressions (§15.28)-are "interned" so as to share unique instances, using the method String.intern.
The reason it returns the same is because of memory optimizations (that aren't always guaranteed to occur) strings with the same content will point to the same memory area to save space. In the case of static objects they will always point to the same thing (as there is only one of it because of the static keyword). Again don't rely on the above and use Equals() instead.
One thing I should point out from Jon Skeet is that it is always guaranteed for compile time constants. But again just use equals() as it is clearer to read.
It is due to string intern pooling
See
whats-the-difference-between-equals-and
The == operator does always compares references in Java and never contents. What can happen is that once you declare a string literal, this object is sent to the JVM's string pool and if you reuse the same literal the same object is going to be placed in there. A simple test for this behavior can be seen in the following code snippet:
String a = "a string";
String b = "a string";
System.out.println( a == b ); // will print true
String c = "other string";
String d = new String( "other string" );
System.out.println( c == d ); // will print false
The second case prints false because the variable d was initialized with a directly created String object and not a literal, so it will not go to the String pool.
The string pool is not part of the java specification and trusting on it's behavior is not advised. You should always use equals to compare objects.
I guess == has been defined the same as equals to prevent its misuse
Wrong. What is happening here is that when the compiler sees that you are using the same string in two different places it only stores it in the program's data section once. Read in a string or create it from smaller strings and then compare them.
Edit: Note that when I say "same string" above, I'm referring only to string literals, which the compiler knows at runtime.

Why does + work with Strings in Java?

Java can't do operator overloading, but + works okay for String and Integer and some other classes. How is this possible?
update:
Why does this work?
Integer i = 4;
Integer p = 5;
System.out.println(i*p); // prints 20
+ is not an example of operator overloading. + is built into the language as a concatentation operator and an arithmetic-addition operator.
What this means is that a person writing a program with Java cannot overload operators, but as far as the grammar of the Java language is concerned, + is defined as a concatenation and an addition operator.
EDIT
It works for other classes such as Integer and Double because of autoboxing.
If you take a look at the bytecode of a Java program that performs string concatenation, you'll see that it creates StringBuilder and uses the append() method. The Java compiler sees the + operator and realizes that the operands are strings and not primitive types (like int).
If you look at the bytecode of a program that does integer addition, you will see that it uses the iadd instruction to perform integer addition. This is because the compiler realizes that the operands to the + operation are integers.
As far as doing something like Integer i = 4, the bytecode will show that you're actually doing Integer i = Integer.valueOf(4). This is called autoboxing. Later on, when you do something like i + p, where both i and p are of type Integer, the generated bytecode will show that you're doing i.intValue() + p.intValue(), where the return types of both methods are int (the actual bytecode instruction again, is iadd).
This is why + works Integer even though they are not actual primitive types.
It works for primitive wrappers like Integer because of autoboxing.
It works for String because that's a special case for concatenating strings:
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion, see Gosling, Joy, and Steele, The Java Language Specification.
+ is a built-in operation. It's an exception, not a rule.
Java doesn't allow custom operator overloading, but the compiler can still be told by the compiler developer that String1 + String2 == String1String2, and to substitute the proper concatenation method call for the + operator.
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings.
String s = "string 1" + "string 2";
What actually is execute is
(new StringBuilder()).append("string 1").append("string 2").toString()
As #yan said, this is the exception, not the rule. Strings have a special status in Java. There's a whole subsection of the Java Language Specification devoted to + in its role as the string concatenation operator: §15.18.1.
Regarding your update, that's another special case. Java is sometimes, depending on the case, smart enough to convert things that are not Strings into Strings when Strings are needed. One of these special cases is the one you described, where primitives are showing up in a place that needs a String. The primitives are first converted to their reference types — Integer, Double, &c. — and then into Strings via the toString() method.
Another special case is when one String and one non-String are being combined with the string concatenation operator +, as described in JLS §5.4 — String Conversion.
For completeness: + in its more common "adding numbers together" role is described in the other part of of §15.18, §15.18.2 — Additive Operators (+ and -) for Numeric Types.

Categories