我如何以编程方式证明StringBuilder不是线程安全的? [英] How do I prove programmatically that StringBuilder is not threadsafe?
问题描述
如何以编程方式证明 StringBuilder
不是线程安全的?
How do I prove programmatically that StringBuilder
is not threadsafe?
我试过这个,但它不是working:
I tried this, but it is not working:
public class Threadsafe {
public static void main(String[] args) throws InterruptedException {
long startdate = System.currentTimeMillis();
MyThread1 mt1 = new MyThread1();
Thread t = new Thread(mt1);
MyThread2 mt2 = new MyThread2();
Thread t0 = new Thread(mt2);
t.start();
t0.start();
t.join();
t0.join();
long enddate = System.currentTimeMillis();
long time = enddate - startdate;
System.out.println(time);
}
String str = "aamir";
StringBuilder sb = new StringBuilder(str);
public void updateme() {
sb.deleteCharAt(2);
System.out.println(sb.toString());
}
public void displayme() {
sb.append("b");
System.out.println(sb.toString());
}
}
class MyThread1 implements Runnable {
Threadsafe sf = new Threadsafe();
public void run() {
sf.updateme();
}
}
class MyThread2 implements Runnable {
Threadsafe sf = new Threadsafe();
public void run() {
sf.displayme();
}
}
推荐答案
问题
我担心您所写的测试不正确。
Problem
I am afraid the test you have written is incorrect.
主要要求是共享 StringBuilder
不同线程之间的实例。而您正在创建 StringBuilder
每个线程的对象。
The main requirement is to share the same StringBuilder
instance between different threads. Whereas you are creating a StringBuilder
object for each thread.
问题是新的Threadsafe()
初始化 new StringBuilder()
:
class Threadsafe {
...
StringBuilder sb = new StringBuilder(str);
...
}
class MyThread1 implements Runnable {
Threadsafe sf = new Threadsafe();
...
}
class MyThread2 implements Runnable {
Threadsafe sf = new Threadsafe();
...
}
说明
要证明 StringBuilder
类不是线程安全的,你需要编写一个测试,其中 n
threads( n> 1
)同时将一些内容附加到同一个实例。
Explanation
To prove the StringBuilder
class is not thread-safe, you need to write a test where n
threads (n > 1
) append some stuff to the same instance simultaneously.
了解要添加的所有内容的大小,您将能够将此值与 builder.toString()。length()
:
Being aware of the size of all the stuff you are going to append, you will be able to compare this value with the result of builder.toString().length()
:
final long SIZE = 1000; // max stream size
final StringBuilder builder = Stream
.generate(() -> "a") // generate an infinite stream of "a"
.limit(SIZE) // make it finite
.parallel() // make it parallel
.reduce(new StringBuilder(), StringBuilder::append, (b1, b2) -> b1);
// put each element in the builder
Assert.assertEquals(SIZE, builder.toString().length());
由于它实际上不是线程安全的,因此您可能无法获得结果。
Since it is actually not thread-safe, you may have trouble getting the result.
ArrayIndexOutOfBoundsException
可能会因为 char [] AbstractStringBuilder#value
数组而被抛出,而且分配机制不是专为多线程使用而设计。
An ArrayIndexOutOfBoundsException
may be thrown because of the char[] AbstractStringBuilder#value
array and the allocation mechanism which was not designed for multithreading use.
这是我的 JUnit 5 测试,涵盖 StringBuilder
和 StringBuffer
:
Here is my JUnit 5 test which covers both StringBuilder
and StringBuffer
:
public class AbstractStringBuilderTest {
@RepeatedTest(10000)
public void testStringBuilder() {
testAbstractStringBuilder(new StringBuilder(), StringBuilder::append);
}
@RepeatedTest(10000)
public void testStringBuffer() {
testAbstractStringBuilder(new StringBuffer(), StringBuffer::append);
}
private <T extends CharSequence> void testAbstractStringBuilder(T builder, BiFunction<T, ? super String, T> accumulator) {
final long SIZE = 1000;
final Supplier<String> GENERATOR = () -> "a";
final CharSequence sequence = Stream
.generate(GENERATOR)
.parallel()
.limit(SIZE)
.reduce(builder, accumulator, (b1, b2) -> b1);
Assertions.assertEquals(
SIZE * GENERATOR.get().length(), // expected
sequence.toString().length() // actual
);
}
}
结果
Results
AbstractStringBuilderTest.testStringBuilder:
10000 total, 165 error, 5988 failed, 3847 passed.
AbstractStringBuilderTest.testStringBuffer:
10000 total, 10000 passed.
这篇关于我如何以编程方式证明StringBuilder不是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!