字符串的plus运算符的线程安全性,包括优化 [英] Thread safety of the plus operator for Strings, optimizations included

查看:138
本文介绍了字符串的plus运算符的线程安全性,包括优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇文章 a + = b 相当于

  a = new StringBuilder()
.append(a)
.append(b)
.toString();

假设我有这段代码:

 公共类MultiThreadingClass扩展SomeThirdPartyClassThatExtendsObject {
public void beginmt(String st)throws IOException {
// st是一个线程号
st = new File( C:\\somepath。)getCanonicalPath()+ \\ + ST;
System.out.println(st);
}
}

假设beginmt同时运行多次(带有线程编号) 1到15500)在MultiThreading类的单个实例上。可能有这样的情况,它可以打印以下,即一些线程数丢失,一些数字加倍?

  c:\\ \\ somepath \\\ 
c:\ somepath \ 1
c:\ somepath \ 1
c:\ somepath \ $ 4
c:\ somepath \ $ 5 b $ bc:\ somepath \ $ 6
c:\ somepath \ $
c:\ somepath \ $ $ $ bc:\ somepath \ $ 8
c:\ somepath \ $
...

编辑:



是否可以安全地说+运算符不会进入某些不安全的发布问题?我认为StringBuilder可以被优化为类似于实例变量的东西,在这种情况下它可能会被不安全地发布。



编辑2:



就JLS,上述帖子以及上述代码的类似类文件进行检查,要使用的StringBuilders似乎必须包含在不同的内容中stackframes。但是,我仍然想检查某种形式的激进优化是否会导致StringBuilders以某种方式被集中式StringBuilder替换。这听起来是可能的,因为当优化器预测对象刚刚以非常数方式实现时实际上这样的对象可以是常量时,优化器优化是合乎逻辑的。



找到 stringopts.cpp 但还没有找到时间来全面检查它。我希望找到涉及此源文件详细信息的答案。



编辑3:



我仍然在寻找包含有关可变对象的主动内联代码的答案。

解决方案

每个帖子都将永远拥有单独的 StringBuilder 实例。
当线程不共享实例时,线程安全没有问题。



所以,以下简单的方法......

  public class MyThreadSafeClass 
{
public String myMethod(String field1,String field2,String field3)
{
return field1 + field2 + field3;
}
}

...将被编译为使用本地StringBuilder 。

  public class MyThreadSafeClass 
{
public String myMethod(String field1,String field2,String field3)
{
返回新的StringBuilder(field1).append(field2).append(field3).toString();
}
}

每次输入方法时,新的 StringBuilder 实例已创建。
此实例仅用于此线程的范围。



你是正确的但是StringBuilders并不总是线程安全的。(见下文)
如果多个线程开始调用 saveEvent 方法,他们可能同时使用该构建器。

 公共类历史
{
//线程安全问题!!!!
//实际上,在这里你应该使用StringBuffer或一些锁定。
private StringBuilder historyBuilder = new StringBuilder();

public void saveEvent(String event)
{
historyBuilder.append(event).append('\ n');
}

public String getHistoryString()
{
return historyBuilder.toString();
}
}

但编译器优化不会创建这些类型

我们可以尝试使事情变得更复杂(静态字段,多个类加载器......),但总是再次,每个 StringBuilder 实例仅由1个线程创建和使用。



编辑:



或许有用的知道:此优化在期间发生生成字节码。稍后在 JIT编译,但这种优化不是其中之一。但JIT编译器确实有一个重要的对最终表现的影响


This post says that a += b is the equivalent of

a = new StringBuilder()
    .append(a)
    .append(b)
    .toString();

Let's say I have this code:

public class MultiThreadingClass extends SomeThirdPartyClassThatExtendsObject{
    public void beginmt(String st) throws IOException {
        //st is a thread number
        st = new File("c:\\somepath").getCanonicalPath()+"\\"+st;
        System.out.println(st);
    }
}

Assume that beginmt runs multiple times simultaneously (with thread numbers 1 to 15500) on a single instance of MultiThreading class. Could there be instances such that it could print the following i.e. some thread numbers are lost and some numbers are doubled?

c:\somepath\2
c:\somepath\1
c:\somepath\1
c:\somepath\4
c:\somepath\5
c:\somepath\6
c:\somepath\7
c:\somepath\8
c:\somepath\8
c:\somepath\10
...

Edit:

Will it be safe to say that the + operator won't get into some unsafe publication issue? I'm thinking the StringBuilder could be optimized into something that resembles an instance variable in which case it could be unsafely published.

Edit 2:

As far as the JLS, the abovementioned post, and a similar class file for the above code are checked, the StringBuilders to be used seem to have to get contained within different stackframes. However, I'd still like to check whether some form of aggressive optimization could cause the StringBuilders to be replaced by a centralized StringBuilder in some way. This sounds possible as it sounds logical for optimizers to optimize when it predicts that an object is just implemented in a non-constant way when in fact such object could be constant.

Found stringopts.cpp but haven't found the time yet to fully check it. I'm hopefully looking for answers involving details of this source file.

Edit 3:

I'm still looking for answers that include code on aggressive inlining for mutable objects.

解决方案

Each thread will always have individual StringBuilder instances. Thread-safety is no issue when threads don't share instances.

So, the following simple method ...

public class MyThreadSafeClass
{
  public String myMethod(String field1, String field2, String field3)
  {
     return field1 + field2 + field3;
  }
}

... will be compiled to use a local StringBuilder.

public class MyThreadSafeClass
{
  public String myMethod(String field1, String field2, String field3)
  {
     return new StringBuilder(field1).append(field2).append(field3).toString();
  }
}

Each time the method is entered, a new StringBuilder instance is created. This instance is only used withing the scope of this thread.

You are correct however that StringBuilders are not always thread-safe. (see below) If multiple threads start calling the saveEvent method, they may be using the builder simultaneously.

public class History
{
  // thread-safety issues !!!! 
  // In fact, here you should use a StringBuffer or some locking.
  private StringBuilder historyBuilder = new StringBuilder();

  public void saveEvent(String event)
  {
     historyBuilder.append(event).append('\n');
  }

  public String getHistoryString()
  {
     return historyBuilder.toString();
  }
}

But compiler optimizations will not create these kind of constructions. The StringBuilder is always created and used only within one and the same thread.

We could try to make things more complex (static fields, multiple classloaders, ...) but always again, each StringBuilder instance is created and used by only 1 thread.

EDIT:

Perhaps useful to know: This optimization happens during the generation of the byte-code. There are other optimizations later on during JIT compilation, but this optimization is not one of them. However the JIT compiler does have an important impact in the final performance.

这篇关于字符串的plus运算符的线程安全性,包括优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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