String thread safety because of immutability? - java

Hi was reading about that a string is thread safe because it is immutable.
For example i do:
String a = "test";
One thread uses this variable.
But another thread could still also use this variable and change it:
a = a + "something";
So it would change or not?
If it would be volatile, i would get it, that it can just be used by one thread at a time. But immutabilty doesnt guarantee me this!?

You're not changing the object pointed by a, but where a points to:
String a = "test";
here a points to a string "test"
a = a + "something";
here a new string is created as the result of the concatenation of "test" and "something", which "testsomething" where a points to. It's a different instance.
So there is no problem of thread safety, as both threads will have their own a referring to the same "test" string object, but once one of those thread will modify the string to be referring the "testsomething" object, the other Thread will still be referring the original "test" object.

The String itself isn't changing, the reference is. It sounds like you need the reference to be final. Immutability guarantees that the Object does not change, not that the reference cannot change. Just mark it like this:
final String a = "test";

You can make the code thread safe trivially by having each thread copy the reference a. In fact, that’s normally what happens anyway, since you usually pass the string to the thread via a parameter.
So both threads hold a reference to the original string, here "test". If thread 1 now modifies a it only modifies this reference. Thread 2 still retains an intact reference to "test" because the string itself (rather than the reference) is immutable.

Strings objects are thread-safe. If your String a is a local variable then this code is still thread-safe. If it is a field of your class than it is your responsibility to guarantee its thread-safety. Thread-safety of String won't magically make your own code thread-safe. You should take care about it.
You can make field volatile then you get visibility among threads. So any thread will see up-to-date value of your field. But you won't get atomicity in this way. Imagine the following. Let a = "test". Thread 1 updates a and thread 2 updates a. They both see current value which is "test". They read it, make new strings by concatenation and update value of a. And what will be that value? It is unknown. It can be "testsomethingsomething" if threads perform their operations strictly one after another. But it can be just "testsomething". For instance:
thread 1 read "test" from a
thread 2 read "test" from a
thread 2 updates a with "testsomething"
thread 1 updates a (remember, it read a as "test" before) with the same "testsomething"
Voila, you've lost an update to your field. To avoid this kind of problem, you should guard all accesses and modifications to your field with synchronization on single lock object.

A lot of confusion here...
What thread safety of some class means is that concurrent use of it's instance
will not destroy it's internal structure.
In our case it is just a warranty that we finally get a "testsomething", but not a mess like
"tsomethingest" or "tesomethingst" or "tseosmtething" or "somethingtest".
Here a "quick and dirty" illustration:
public class Test2 {
private volatile String tstStr = "";
Test2(){
}
void impl(int par){
Thread wrk = new Thread(new MyRun(par));
wrk.start();
}
static public void main(String[] args) throws Exception {
Test2 tst2 = new Test2();
long startTime = System.currentTimeMillis();
Thread wrk;
for (int i = 0; i < 9; i=i+1) {
tst2.impl(i);
}
long endTime = System.currentTimeMillis();
System.out.println("The process took " + (endTime - startTime) + " milliseconds");
}
class MyRun implements Runnable {
int no;
MyRun(int var){
no = var;
}
public void run(){
tstStr = tstStr + " " + no;
for (int i = 0; i < 3; i=i+1) {
System.out.println("Message from "+no+", tested string ="+tstStr);
}
}
}
}
The output:
Message from 1, tested string = 0
Message from 1, tested string = 0 2 3
Message from 1, tested string = 0 2 3
Message from 4, tested string = 0 2 3 4
Message from 4, tested string = 0 2 3 4
Message from 0, tested string = 0 2
Message from 8, tested string = 0 2 3 4 7 8
Message from 5, tested string = 0 2 3 4 7 8 5
Message from 0, tested string = 0 2 3 4 7 8 5
Message from 0, tested string = 0 2 3 4 7 8 5
The process took 0 milliseconds
Message from 7, tested string = 0 2 3 4 7
Message from 7, tested string = 0 2 3 4 7 8 5 6
Message from 4, tested string = 0 2 3 4
Message from 3, tested string = 0 2 3
Message from 2, tested string = 0 2
Message from 3, tested string = 0 2 3 4 7 8 5 6
Message from 7, tested string = 0 2 3 4 7 8 5 6
Message from 6, tested string = 0 2 3 4 7 8 5 6
Message from 5, tested string = 0 2 3 4 7 8 5
Message from 8, tested string = 0 2 3 4 7 8 5
Message from 5, tested string = 0 2 3 4 7 8 5 6
Message from 6, tested string = 0 2 3 4 7 8 5 6
Message from 3, tested string = 0 2 3 4 7 8 5 6
Message from 2, tested string = 0 2 3 4 7 8 5 6
Message from 6, tested string = 0 2 3 4 7 8 5 6
Message from 8, tested string = 0 2 3 4 7 8 5 6
Message from 2, tested string = 0 2 3 4 7 8 5 6

Related

Synchronized Thread in Java

I have 3 class like this:
Source.java
public class Source extends Thread{
private int x= 0;
public void increment(int id){
x++;
System.out.println(id+" "+x);
}
}
Task.java
public class Task extends Thread{
private Source source;
private int id;
public Task(Source source, int id){
this.source=source;
this.id=id;
}
public void run(){
for (int i=0;i<100;i++){
try{Thread.sleep(1000);}catch(InterruptedException e){}
source.inc(id);
}
}
}
Main.java
public class Main{
public static void main(String[] args) throws IOException{
Source source = new Source();
Task t1=new Task(source,1);
Task t2=new Task(source,2);
t1.start();
t2.start();
}
}
I want when the x of the class Source will be equal to 4 only one task continues to increment x until x is equal to 8, we return to normal.
The result will look like this:
1 1
2 2
1 3
2 4
1 5
1 6
1 7
1 8
1 9
1 10
2 11
1 12
2 13
...
How do I modify the code to achieve the desired result?
Basically you have two threads that modify the same variable x. There is no garantee about the order of execution.
You should synchronize.
With your current implementation you may face a problem (The race condition problem): Race condition example
Something like this is an scenario that most likely is going to happen to you:
....
1 3
2 4
2 5
1 6
1 7
2 7
1 8
2 9
1 10
2 10
...
As you can see the thread 2 (source 2) tries to increment the variable x when the variable has been already incremented but the value it has to increment is the old one.
x = 0
Thread 1 reads the variable x (0)
Thread 2 reads the variable x (0)
Thread 1 increments variable x + 1 (0 + 1) = 1
Thread 2 increments variable x + 1 (0 + 1) = 1
In order to solve this you need to synchronize your variable, an AtomicInteger would be enough. + I don't think you need the extends Thread on your Source class, you can get rid of it

System.out.println with java volatile

I have an example like that:
public class MainApp {
private volatile static int MY_INT = 0;
public static void main(String[] args) {
new Thread1().start();
new Thread2().start();
}
static class Thread1 extends Thread {
#Override
public void run() {
while(true) {
MY_INT++;
System.out.println("1 : " + MY_INT);
}
}
}
static class Thread2 extends Thread{
#Override
public void run() {
while(true) {
MY_INT++;
System.out.println("2 : " + MY_INT);
}
}
}
}
And the output is:
1 : 1
2 : 2
1 : 3
2 : 4
1 : 5
1 : 7
1 : 8
1 : 9
1 : 10
2 : 6
1 : 11
1 : 13
I don't understand why after printing 1:10 and the next line is 2:6. Can anyone explain the result? Thanks in advance
There are several issues here:
threads may not run in parallel. They run in time slices (default: 15.6 ms on a PC; 64 ticks per second, see timer resolution (Microsoft)). This is why you don't see 1:x and 2:x one after another, but several 1:x after each other.
using volatile does not help with synchronization. You need real synchronization objects such as AtomicInteger or the synchronized keyword. Therefore you may see skipped numbers (not the case in your output, but it may occur). You need the synchronization around both, the ++ and the println() if you want to see unique numbers
Console output is buffered and synchronized, because you don't want 2 println statements to mix the output on one line
The PrintStream in System.out and the volatile field MY_INT are independently synchronized, so the following can happen:
Thread 1 Thread 2
read MY_INT = 4
write MY_INT = 5
read MY_INT = 5
read MY_INT = 5
write MY_INT = 6
read MY_INT = 6
println 5
read MY_INT = 6
write MY_INT = 7
read MY_INT = 7
println 7
...
println 6
That is, because the volatile field and the PrintStream returned by System.out are independently synchronized, printing may occur in non-ascending order.
The following could also happen:
Thread 1 Thread 2
read MY_INT = 1
read MY_INT = 1
write MY_INT = 2
write MY_INT = 2
read MY_INT = 2
println 2
read MY_INT = 2
println 2
because ++MY_INT is actually compiled into a read, a computation, and a write. Since volatile reads and writes are separate synchronization actions, other threads may act in between, and mess the counter up.
If you want ascending numbers being printed by separate threads, the easiest way is:
void run() {
while (true) {
synchronized (lock) {
MY_INT++;
System.out.println("1 : " + MY_INT);
}
}
}
where lock is an object shared by all threads accessing MY_INT.

Variable that can be read by all Async Tasks

What I am trying to do involves keeping track of a variable while it prints an array out. However, what makes it confusing is that it is Asynchronous.
This is similar to what I have now.
public static int variable = 0;
public void print()
{
System.out.println(array[variable]);
variable ++;
}
Then another class with an ExecutorService and CompletionService that calls the print() method asynchronously which runs around 40 jobs with 4 threads (in my example its 11 jobs).
The problem (how I see it) is that since it is running asynchronously, 4 threads have the same value of variable or it skips some values because 2 threads finished at the same time therefore it incremented by 2.
I printed out the variable values and here are some results:
0 1 2 2 2 2 6 6 6 9 10
0 1 2 2 4 4 6 7 8 9 10
0 1 1 1 1 5 6 7 8 8 8
Declare the method print() synchronized.
Or declare the variable variable as AtomicInteger instead of int.
You could create a new class that handles printing:
public class SyncPrinter {
public static int variable = 0;
public static synchronized void print()
{
System.out.println(array[variable]);
variable ++;
}
}
Then call it as SyncPrinter.print()

External file with multiple numbers per line Java

I need help reading an external file that has more than one number per line. Here is the external data file:
1 1
2 3
3 5
4 7
5 2
6 4
1 6
2 8
3 1
4 3
5 5
6 7
1 8
2 1
3 2
4 3
5 4
6 5
I read it in by using
public class Prog435a
{
public static void main(String[] args) throws IOException
{
Scanner kbReader = new Scanner(new File("C:\\Users\\Super Mario\\Documents\\java programs\\Prog435\\Prog435a.in"));
while(kbReader.hasNext())
{
int data = kbReader.nextInt();
System.out.println(data);
}
}
}
However, it prints out the file with each number line by line. So instead of appearing in columns, it appears in a single column. How can I get this to print out in two columns as shown above? Thanks for the help.
Loop by line. Call nextInt() two times per line.
while(kbReader.hasNextLine()) {
System.out.println(kbReader.nextInt() + " " + kbReader.nextInt());
}

Java string split function acting strange

I am noticing strange behaviour when using the split() method in Java.
I have a string as follows: 0|1|2|3|4|5|6|7|8|9|10
String currentString[] = br.readLine().split("\\|");
System.out.println("Length:"+currentString.length);
for(int i=0;i < currentString.length;i++){
System.out.println(currentString[i]);
}
This will produce the desired results:
Length: 11
0
1
2
3
4
5
6
7
8
9
10
However if I receive the string: 0|1|2|3|4|5|6|7|8||
I get the following results:
Length: 8
0
1
2
3
4
5
6
7
8
The final 2 empties are omitted. I need the empties to be kept. Not sure what i am doing wrong. I have also tried using the split in this manner as well. ...split("\\|",-1);
but that returns the entire string with a length of 1.
Any help would be greatly appreciated!
The default behavior of split is to not return empty tokens (because of a zero limit). Use the two parameter split method with a limit of -1 will give you all empty tokens in the return.
UPDATE:
Test code as follows:
public class Test {
public static void main(String[] args) {
String currentString[] = "0|1|2|3|4|5|6|7|8||".split("\\|", -1);
System.out.println("Length:"+currentString.length);
for(int i=0;i < currentString.length;i++){ System.out.println(currentString[i]); }
}
}
Output as follows:
Length:11
0
1
2
3
4
5
6
7
8
--- BLANK LINE --
--- BLANK LINE --
The "--- BLANK LINE --" is put in by me to show that the return is blank. It is blank once for the empty token after 8| and once for the empty trailing token after the last |.
Hope this clears things up.
String.split() is weird.
Its extreme weirdness, in this and other ways, are some of the reasons why we made Splitter.
It has less surprising behavior and lots of flexibility.
My Java is a little bit rusty, but shouldn't it be:
String currentString[] = "0|1|2|3|4|5|6|7|8||".split("\\|");
System.out.println("Length:"+currentString.length);
for(int i = 0; i < currentString.length; i++)
{
System.out.println(currentString[i]);
}
IMO, I think this is the default behavior of split, Anyway please try this:
String currentString[] = br.readLine().replace("||","| |").split("\|");
System.out.println("Length:"+currentString.length);
for(int i=0;i < currentString.length;i++){
System.out.println(currentString[i]);
}
This has not been tested yet, but i think this should do the trick.
You need to use indexOf() and then substring() for this to work. I don't think you can empty string by using split() only.
Please check the following code, I used your solution, it works:
public class SplitTest
{
public static void main(String[] args)
{
String text = "0|1|2|3|4|5|6|7|8||";
String pattern = "\\|";
String [] array = text.split(pattern, -1);
System.out.println("array length:" + array.length);
for(int i=0; i&lt array.length; i++)
System.out.print(array[i]+ " ");
}
}
output is:
array length:11
0 1 2 3 4 5 6 7 8

Categories

Resources