浅谈Java StringBuilder为什么线程不安全
Java StringBuilder是一个可变的字符串对象,它可以动态地增加或删除字符,然而,它却不是线程安全的。在多线程环境下,使用StringBuilder可能会出现一些问题,例如输出值不正确、抛出ArrayIndexOutOfBoundsException异常等。
StringBuilder和StringBuffer都是通过一个char数组存储字符串的,不同的是String类里的char数组是final修饰的,是不可变的,而StringBuilder和StringBuffer的char数组是可变的。
在多线程环境下,使用StringBuilder可能会出现问题。例如,在上面的代码中,我们创建了10个线程,每个线程循环1000次往StringBuilder对象里面append字符。正常情况下,代码应该输出10000,但是实际运行会输出小于10000的值,并且还抛出了一个ArrayIndexOutOfBoundsException异常。
为什么输出值跟预期值不一样?这是因为StringBuilder的append()方法不是线程安全的。在多线程环境下,多个线程同时执行append()方法可能会出现问题。例如,在append()方法中,有一行代码`count += len;`,这不是一个原子操作。如果两个线程同时执行到这行代码,拿到的count值都是10,执行完加法运算后将结果赋值给count,所以两个线程执行完后count值为11,而不是12。这就是为什么测试代码输出的值要比10000小的原因。
为什么会抛出ArrayIndexOutOfBoundsException异常?这是因为在AbstractStringBuilder的append()方法中,有一行代码`str.getChars(0, len, value, count);`,如果count值大于value数组的长度就会抛出ArrayIndexOutOfBoundsException异常。在多线程环境下,count值可能会被多个线程同时修改,导致count值大于value数组的长度,从而抛出异常。
Java StringBuilder不是线程安全的,在多线程环境下使用StringBuilder可能会出现问题。如果需要在多线程环境下使用StringBuilder,需要使用同步机制来确保线程安全。例如,可以使用StringBuffer,它是线程安全的。