我们知道StringBuffer是线程安全的,StringBuilder是非线程安全的,但是这个安全并不是绝对的。
StringBuffer的方法都加了synchronized关键字来保证每一次方法调用都是线程安全的,但是如果多个线程同时调用StringBuffer的append的方法仍然是有问题的,看下面的例子。
我们有一个单例类
public class Single {
private static Single single;
public StringBuffer sbf;
private Single() {
}
public static Single getInstance() {
synchronized (Single.class) {
if (Single.single == null) {
Single.single = new Single();
}
}
return Single.single;
}
}
下面是测试类
public class Mythread implements Runnable {
@Override
public void run() {
Single single = Single.getInstance();
String name = Thread.currentThread().getName();
single.sbf = new StringBuffer();
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
single.sbf.append("put name " + name + " ");
System.out.println(name + " : " + single.sbf.toString());
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Mythread()).start();
}
}
}
运行结果会像下面这样:
Thread-8 : put name Thread-5 put name Thread-6 put name Thread-8
Thread-6 : put name Thread-5 put name Thread-6 put name Thread-8 put name Thread-7 put name Thread-9
Thread-7 : put name Thread-5 put name Thread-6 put name Thread-8 put name Thread-7
Thread-9 : put name Thread-5 put name Thread-6
Thread-5 : put name Thread-5 put name Thread-6 put name Thread-8 put name Thread-7
所以StringBuffer只是保证在调用它的append方法的时候,别的线程不能调用,但是交替的调用append方法是可以的。
如果要想输出
Thread-5 : put name Thread-5
Thread-6 : put name Thread-6
Thread-8 : put name Thread-8
Thread-7 : put name Thread-7
Thread-9 : put name Thread-9
那我们要在run方法里面加锁,像下面这样
synchronized(single){
single.sbf = new StringBuffer();
try {
Thread.currentThread();
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
single.sbf.append("put name " + name + " ");
System.out.println(name + " : " + single.sbf.toString());
}