May I hope that you have gone through Difference between StringBuffer and StringBuilder before reading this topic.
All the public methods within StringBuffer are synchronized, which means a method invocation on a StringBuffer instance acts as an atomic operation.i.e.a method execution by one thread can't be interrupted by another thread.
But one point to remember is that,two or more sequential method invocations on a StringBuffer instance by a thread is not synchronized i.e. it is not an atomic operation.
Consider one example
public class Main {
public static void main(String[] args) throws InterruptedException {
StringBuffer resource = new StringBuffer();
MyThread t1 = new MyThread(resource);
t1.setName("t1");
MyThread t2 = new MyThread(resource);
t2.setName("t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(resource);
}
}
class MyThread extends Thread {
StringBuffer resource;
MyThread(StringBuffer resource) {
this.resource = resource;
}
public void run() {
resource.append(Thread.currentThread().getName() + "->1 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->2 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->3 ");
}
}
In the above example,two threads t1 and t2 invoking append method three times sequentially with an interval of 1 second.But you can never confirm that both the threads execute all the three invocation in order .i.e.one thread finishes all the three invocation then the second thread.The order of invocation of method by one thread may be interrupted by another thread.
In the above example,
the expected output is
t2->1 t2->2 t2->3 t1->1 t1->2 t1->3
or
t1->1 t1->2 t1->3 t2->1 t2->2 t2->3
But the actual output is
t2->1 t1->1 t1->2 t2->2 t2->3 t1->3
That means "only a single method invocation by a thread is an atomic operation not the multiple method invocations "
In order to make multiple StringBuffer method invocation by a thread in exact order you have to synchronize it externally.See the implementation below
public class Main {
public static void main(String[] args) throws InterruptedException {
StringBuffer resource = new StringBuffer();
MyThread t1 = new MyThread(resource);
t1.setName("t1");
MyThread t2 = new MyThread(resource);
t2.setName("t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(resource);
}
}
class MyThread extends Thread {
static Object lock = new Object();
StringBuffer resource;
MyThread(StringBuffer resource) {
this.resource = resource;
}
public void run() {
synchronized (lock) {
resource.append(Thread.currentThread().getName() + "->1 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->2 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->3 ");
}
}
}
Here you always get the output as
t1->1 t1->2 t1->3 t2->1 t2->2 t2->3
or
t2->1 t2->2 t2->3 t1->1 t1->2 t1->3
The links that may help you
Difference between volatile and synchronized in Java
Use of synchronization with examples in Java
All the public methods within StringBuffer are synchronized, which means a method invocation on a StringBuffer instance acts as an atomic operation.i.e.a method execution by one thread can't be interrupted by another thread.
But one point to remember is that,two or more sequential method invocations on a StringBuffer instance by a thread is not synchronized i.e. it is not an atomic operation.
Consider one example
public class Main {
public static void main(String[] args) throws InterruptedException {
StringBuffer resource = new StringBuffer();
MyThread t1 = new MyThread(resource);
t1.setName("t1");
MyThread t2 = new MyThread(resource);
t2.setName("t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(resource);
}
}
class MyThread extends Thread {
StringBuffer resource;
MyThread(StringBuffer resource) {
this.resource = resource;
}
public void run() {
resource.append(Thread.currentThread().getName() + "->1 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->2 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->3 ");
}
}
In the above example,two threads t1 and t2 invoking append method three times sequentially with an interval of 1 second.But you can never confirm that both the threads execute all the three invocation in order .i.e.one thread finishes all the three invocation then the second thread.The order of invocation of method by one thread may be interrupted by another thread.
In the above example,
the expected output is
t2->1 t2->2 t2->3 t1->1 t1->2 t1->3
t1->1 t1->2 t1->3 t2->1 t2->2 t2->3
But the actual output is
t2->1 t1->1 t1->2 t2->2 t2->3 t1->3
That means "only a single method invocation by a thread is an atomic operation not the multiple method invocations "
In order to make multiple StringBuffer method invocation by a thread in exact order you have to synchronize it externally.See the implementation below
public class Main {
public static void main(String[] args) throws InterruptedException {
StringBuffer resource = new StringBuffer();
MyThread t1 = new MyThread(resource);
t1.setName("t1");
MyThread t2 = new MyThread(resource);
t2.setName("t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(resource);
}
}
class MyThread extends Thread {
static Object lock = new Object();
StringBuffer resource;
MyThread(StringBuffer resource) {
this.resource = resource;
}
public void run() {
synchronized (lock) {
resource.append(Thread.currentThread().getName() + "->1 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->2 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
resource.append(Thread.currentThread().getName() + "->3 ");
}
}
}
Here you always get the output as
t1->1 t1->2 t1->3 t2->1 t2->2 t2->3
or
t2->1 t2->2 t2->3 t1->1 t1->2 t1->3
The links that may help you
Difference between volatile and synchronized in Java
Use of synchronization with examples in Java
No comments:
Post a Comment