我如何以编程方式证明StringBuilder不是线程安全的? [英] How do I prove programmatically that StringBuilder is not threadsafe?

查看:86
本文介绍了我如何以编程方式证明StringBuilder不是线程安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何以编程方式证明 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆