StringBuffer 和 StringBuilder 都继承于 AbstractStringBuilder类。然而StringBuffer 是线程安全的,StringBuillder是线程不安全的
先来了解下StringBuillder为啥线程不安全的 。
如果我们循环创建10个线程,并且每个线程都循环往StringBuillder的字符串中添加字符,那么最后的运行结果会是多少?
public static void main(String args[]){ // Windows w1 = new Windows(); // Thread t1 = new Thread(w1);Thread t2 = new Thread(w1);Thread t3 = new Thread(w1); // t1.start();t2.start();t3.start(); // StringBuilder s = new StringBuilder(); for(int i=0;i<9;i++){ new Thread(new Runnable() { @Override public void run() { for(int j=0;j<100;j++){ s.append('a'); } } }).start(); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(s.length()); }
最后字符串s的长度应该是90,但是当我们执行完后的长度却是 20 而且还有可能 抛出如下异常
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 16 at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:650) at java.lang.StringBuilder.append(StringBuilder.java:202) at ThreadLearn.WindowsTest$1.run(WindowsTest.java:61) at java.lang.Thread.run(Thread.java:748)
要想解决这些问题,我们需要看向字符串的append方法,不难发现,其调用的是AbstractStringBuillder的append方法,此方法逻辑如下:
1 获得需要添加的字符串的length
2 判断是否能够放下新添加的字符串并进行扩充
3 修改value 数组 和 字符串的长度
当我们用两个线程同时去填下相同长度的字符串的时候,在进行容量判断的时候,很明显,每个线程都会的到相同地结果,将字符串扩充到
相应的数值,但这个数值可能只可以放得下一个线程的字符串却放不下两个的,因此就会出现 数组越界的异常而同时,扩充后的字符串的长度
也会不正常。
然而StringBuffer却不会出现这个问题,因为其给append方法添加了 锁,实现了线程同步。