Reputation: 2663
Suppose I have a class in which there is a StringBuffer declared as a member variable. Two threads are trying to manipulate the object like below
public class SomeService {
private StringBuffer sb = new StringBuffer();
public void printName(String name) {
sb.append(name);
System.out.println(sb);
}
}
public class StringBufferSynchronizationTest implements Runnable {
private SomeService service = new SomeService();
public StringBufferSynchronizationTest() {
Thread thread = new Thread(this);
thread.start();
}
public static void main(String[] args) {
new StringBufferSynchronizationTest().service.printName("oops");
}
@Override
public void run() {
service.printName("java");
}
}
And I get this output
oopsjava
oopsjava
I thought I will get
oops
oopsjava
as output. When I synchronized printName method I got the second output.
So I understood that even I use a synchronized class I have to synchronize blocks/methods that use the synchronized classes. Am I right?
Upvotes: 1
Views: 567
Reputation: 592
It depends on what you are trying to accomplish.
Let us take a look at printName
public void printName(String name) {
sb.append(name);
System.out.println(sb);
}
Since sb in synchronized, sb.append(name)
has only 1 thread operating on the objects mutable state. This prevents Strings, in your example, of the values
oojavaps
ojopsava
and so on. However since your printName method is not synchronized you have no guarantees on the order of invocation of the 2 methods within printName across 2 threads.
The easiest way to understand it is probably to come up with the sequence of execution that results in the output
oopsjava
oopsjava
Initially sb
is the empty String
Assume the main thread executes sb.append(name)
, leaving sb
with oops
, however it is preempted before it can execute the println
The constructor thread takes over and execute the entire method, first appending java
to sb
to get oopsjava
in sb
and then printing the output, to get
oopsjava
The main thread then executes, printing sb
to get
oopsjava
I had one example of output here that was incorrect, @Cruncher pointed this out in the comments and I removed it.
Upvotes: 1
Reputation: 542
Yes, the StringBuffer is synchronized, If you want the expected result, synchronized also the function printName. Context switch can be occur between sb.append(name);
and System.out.println(sb);
especially it is related to slow IO.
public synchronized void printName(String name) {
sb.append(name);
System.out.println(sb);
}
Upvotes: 1
Reputation: 135992
StringBuffer guarantees that only one thread can enter append or any other method of the same instance. But this is all, there are no more guarantees.
Upvotes: 1