以原子方式将新字符连接到StringBuilder对象



我的问题是:

我有课:

public class AtomicStringBuilder {
private final AtomicReference<StringBuilder> sbRef;
}

我需要同时和原子地向StringBuilder添加新字符。但问题是,这个对象中应该只有最后128个字符。我不能使用StringBuffer,因为操作应该是非阻塞的。

因此,有两种操作:

首先:检查StringBuilder是否已经有128个字符。

第二:如果没有->添加新的字符,如果它有->删除第一个字符并添加新字符。

有没有办法使这两个或三个操作成为原子操作?

我做了这个方法,但它不起作用:

public void append(String string) {
this.sbRef.getAndUpdate(ref -> {
if (ref.length() < 128) {
ref.append(string);
} else {
ref.append(string).delete(0, ref.length() - 128);
}
return ref;
});
}

为了测试,我创建了这个方法:

public void test() {
AtomicStringBuilder atomicStringBuilder = new AtomicStringBuilder();
Random random = new Random();
Stream<Integer> infiniteStream = Stream.iterate(0, i -> random.nextInt(10));
infiniteStream.parallel()
.limit(100000)
.forEach(integer -> atomicStringBuilder.append(String.valueOf(integer)));
assertEquals(128, atomicStringBuilder.getSb().get().length());
}

这不是一个真正的prolem,我可以用任何其他可行的东西来更改AtomicReference。任务是创建无锁定且没有比赛条件的操作

这里有一个不可变字符串的解决方案。

如果你使用AtomicReference,你需要返回一个新的引用,而不是改变引用指向的对象。原子比较引用的当前值和期望值是知道它没有被另一个线程更新的唯一方法。

getAndUpdate这样做:

  1. 获取当前引用
  2. 将lambda应用于引用,获得新的引用
  3. 如果当前引用没有更改,则原子地将其设置为新引用,否则返回到1
public class App {
static class AtomicStringBuilder {
public final AtomicInteger counter = new AtomicInteger();
public final AtomicReference<String> sbRef = new AtomicReference<>("");
public void append(String string) {
this.sbRef.getAndUpdate(ref -> {
counter.getAndIncrement();
if (ref.length() < 128) {
return ref + string;
} else {
String s = ref + string;
return s.substring(s.length() - 128);
}
});
}
}
static void test() {
AtomicStringBuilder atomicStringBuilder = new AtomicStringBuilder();
Random random = new Random();
Stream<Integer> infiniteStream = Stream.iterate(0, i -> random.nextInt(10));
infiniteStream.parallel()
.limit(100000)
.forEach(integer -> atomicStringBuilder.append(String.valueOf(integer)));
if (128 != atomicStringBuilder.sbRef.get().length()) {
System.out.println("failed ");
}
System.out.println(atomicStringBuilder.sbRef.get());
System.out.println(atomicStringBuilder.counter.get());
}
public static void main(String[] args) {
test();
}
}

我在lambda中添加了一个计数器。运行此程序后显示的值将超过100000,因为并发更新强制重试。

最新更新