Krishna Chaitanya
Krishna Chaitanya

Reputation: 2663

Synchronized objects accessed from unsynchronized methods

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

Answers (3)

Bhaskar
Bhaskar

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

tom87416
tom87416

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

Evgeniy Dorofeev
Evgeniy Dorofeev

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

Related Questions