Problème
Je crains que le test que vous avez écrit est incorrecte.
La principale exigence est de partager le même StringBuilder
exemple entre les différents threads. Alors que vous êtes la création d'un StringBuilder
objet pour chaque thread.
Le problème est qu'un new Threadsafe()
initialise un 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();
...
}
Explication
Pour prouver l' StringBuilder
classe n'est pas thread-safe, vous avez besoin d'écrire un essai où n
threads (n > 1
) l'ajout de certains trucs à la même instance simultanément.
Être conscient de la taille de tous les trucs que vous allez à ajouter, vous serez en mesure de comparer cette valeur avec le résultat de l' 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());
Car c'est pas thread-safe, vous pourriez avoir de la difficulté à obtenir le résultat.
Un ArrayIndexOutOfBoundsException
peut être jeté en raison de l' char[] AbstractStringBuilder#value
tableau et le mécanisme d'allocation qui n'a pas été conçu pour utiliser le multithreading.
Test
Voici mon JUnit 5 test qui couvre à la fois StringBuilder
et 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
);
}
}
Résultats
AbstractStringBuilderTest.testStringBuilder:
10000 total, 165 error, 5988 failed, 3847 passed.
AbstractStringBuilderTest.testStringBuffer:
10000 total, 10000 passed.