当前位置: 首页 > 面试题库 >

字符串的plus运算符的线程安全性,包括优化

黄无尘
2023-03-14
问题内容

这篇文章说,a += b相当于

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

假设我有以下代码:

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);
    }
}

假设beginmt在MultiThreading类的单个实例上同时运行多次(线程号为1至15500)。是否可能存在这样的实例,它可以打印以下内容,即某些线程号丢失并且某些数字加倍?

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
...

编辑:

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

编辑2:

只要检查了JLS,上面提到的帖子以及上面代码的类似类文件,要使用的StringBuilders似乎必须包含在不同的堆栈框架中。但是,我仍然想检查某种形式的积极优化是否可能以某种方式使StringBuilder被集中式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)
  {
     return new StringBuilder(field1).append(field2).append(field3).toString();
  }
}

每次输入方法时,StringBuilder都会创建一个新实例。该实例仅在该线程的范围内使用。

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

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();
  }
}

但是编译器优化不会创建这种构造。StringBuilder始终创建并只在同一个线程中使用。

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

编辑:

可能有用的知识:这种优化发生 在字节码的生成过程中
。稍后在JIT编译过程中还有其他优化,但是这种优化不是其中之一。但是,JIT编译器确实会对最终性能产生重要影响。



 类似资料:
  • 问题内容: 我发现以下Java代码。 其中,和是。 我知道基本类型的基本操作是线程安全的,但是我不确定。如果上述是必要的,是否可能有更好的类来处理这种操作? 问题答案: 否。该操作不是线程安全的。对于涉及分配给共享字段或数组元素的任何表达式,它要求锁定和/或适当的“先于”关系链是线程安全的。 (在字段声明为的情况下,“先发生”关系存在…但是仅在读和写操作上存在。该操作由一个读和一个写操作组成。它们

  • 问题内容: 我想创建一个非线程安全的代码块进行实验,这些是2个线程将要调用的函数。 此代码线程安全吗? 如果不是,我可以理解为什么它不是线程安全的,以及通常使用哪种语句导致非线程安全的操作。 如果它是线程安全的,如何使它显式地成为非线程安全的? 问题答案: 由于有GIL,单个操作码是线程安全的,但除此之外: *多个线程共享的 *每个 资源都 必须 有一个锁。

  • 问题内容: 我正在用Java编写一个程序,使一些汽车相互竞争。每辆车都是单独的线程。 当汽车完成比赛时,每个人都会调用此方法。我已经在不同的计时器速度下测试了该方法,并且看起来效果很好。但是我确实意识到每个线程都在访问变量carsComplete,有时恰好在同一时间(至少在date命令给我的范围内)。 所以我的问题是:这个方法是线程安全的吗? 问题答案: 不,您应该使用。看看它的方法。

  • 问题内容: 我对String串联感到困惑。 输出为: 50abc20 50abc1010 我想知道为什么在两种情况下都将 20 + 30 加在一起,但是 10 + 10 需要加上括号(s1)而不是串联到String(s2)。请在此处说明String运算符的工作方式。 问题答案: 加法保持关联。以第一种情况 在第二种情况下:

  • 目标 了解实例化 String 对象和设置其值的多种方法 了解字符串串联和方法链 熟悉 Java 语言的算术运算符 字符串 目前为止,您已经遇到过多种类型的 String。在 Java 语言中,字符串是 String 类型的一级对象,包含可帮助您处理它们的方法。 在 C 语言中,处理字符串需要大量精力,因为它们是您必须操作的 8 位字符组成的以 null 结尾的数组。(在字符串方面,与 C 语言最

  • 现在的Rust资料,无论是Book还是RustByExample都没有统一而完全的介绍Rust的操作符。一个很重要的原因就是,Rust的操作符号和C++大部分都是一模一样的。 一元操作符 顾名思义,一元操作符是专门对一个Rust元素进行操纵的操作符,主要包括以下几个: -: 取负,专门用于数值类型。 *: 解引用。这是一个很有用的符号,和Deref(DerefMut)这个trait关联密切。 !: