对于多线程应用程序,为啥需要同步实现(如果要求没有说明)
Posted
技术标签:
【中文标题】对于多线程应用程序,为啥需要同步实现(如果要求没有说明)【英文标题】:For a multi-threaded application why is it required to go for a synchronized implementation (if the requirement doesn't state that)对于多线程应用程序,为什么需要同步实现(如果要求没有说明) 【发布时间】:2021-12-06 19:39:14 【问题描述】:我有一个非常基本的问题。我已经读过,如果我们有一个多线程应用程序,那么最好使用StringBuffer
。但是如果我们有一个单线程应用程序,那么最好使用StringBuilder
。
但是,拥有多线程应用程序的全部意义不在于所有线程可以同时在同一段代码上工作吗?不应该要求如果我们不希望String同时被所有线程操作,那么我们应该选择StringBuffer
,否则就可以选择StringBuilder
?我想了解的是对于多线程应用程序,为什么需要进行同步实现(如果要求没有说明)。
【问题讨论】:
您将“同步”与“同步”混淆了。这不是一回事。你在哪里读到这个?首先让多个线程在同一个字符串构建器/缓冲区上工作是极其罕见的。使用 Java 25 年从来没有这样做过。 【参考方案1】: StringBuffer 一直“永远”存在。它是线程安全的。 StringBuilder 是“较新的”(在 Java 1.5 中首次引入)。 String 是不可变的。 StringBuffer 和 StringBuilder 都是可变的。使用 StringBuffer 或 StringBuilder VASTLY 比修改原始字符串更有效。根据文档:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StringBuilder.html
[StringBuilder] 是可变的字符序列。这个类提供 与 StringBuffer 兼容的 API,但不保证 同步。此类旨在用作插入式 在字符串缓冲区所在的地方替换 StringBuffer 由单个线程使用(通常是这种情况)。在哪里 可能,建议优先使用此类 StringBuffer,因为它在大多数实现下会更快。
就我个人而言,我总是优先使用 StringBuffer 而不是处理原始字符串。主要是出于习惯。
是的,StringBuilder 可能“更快”。或者,很可能,它对整体“性能”几乎没有影响。
要记住的关键点:
如果可以改用 StringBuilder 或 StringBuffer,请不要直接操作字符串。 StringBuilder 是非同步的(即不是线程安全的)。如果两个线程碰巧同时使用 StringBuilder,结果将是不确定的。您可能也对此感兴趣:
https://www.javatpoint.com/mutable-and-immutable-in-java
什么是可变对象?
可变对象是初始化后可以更改其值的对象。我们可以改变对象的 对象创建后的值,例如字段和状态。为了 例如,Java.util.Date、StringBuilder、StringBuffer 等。
当我们对现有的可变对象进行更改时,不会有新的对象 被创建;相反,它将改变现有对象的值。 这些对象的类提供了对其进行更改的方法。
【讨论】:
请注意,在相对较少的情况下,多个线程可以有意义地共享一个 StringBuffer 而不需要超出该类的内置同步。如果两个线程同时执行 Append 操作,并且结果必须包含以某种任意方式交错的附加字符串,则 StringBuffer 提供的同步可能就足够了,但大多数应用程序要么不会有两个线程尝试同时执行 Append 操作,或者对组合字符串的顺序有更高的要求。 @Louis Wasserman - 感谢您纠正我的错字:)【参考方案2】:我读到如果我们有一个多线程应用程序,那么最好使用 StringBuffer。但如果我们有一个单线程应用程序,那么最好使用 StringBuilder。
对于一个通常很复杂的问题,这是一个非常简单的答案。答案应该是,如果多个线程更新同一个字符串附加程序,你应该使用StringBuffer
。如果您有两个线程并且每个线程都使用自己的本地字符串附加程序,那么无需为StringBuffer
同步付费,可以使用StringBuilder
。您应该知道,无论何时使用字符串 +
运算符,都会在后台创建 StringBuilder
。但归根结底,我从未见过多个线程共享一个字符串 appender 的情况。
但拥有多线程应用程序的全部意义不在于所有线程可以同时处理同一段代码吗?
没有。编写多线程应用程序的原因有很多。 Web 服务器使用多个线程,因此 Web 请求可以异步并行处理,而无需共享任何代码或数据。
不应该要求如果我们不希望String同时被所有线程操作,那么我们应该使用StringBuffer,否则就可以使用StringBuilder?
不完全是。不要认为StringBuffer
会阻止多个线程操作缓冲区。认为它保护缓冲区免受多个线程的不当访问,这会导致竞争条件和其他意外后果。
我想了解的是对于多线程应用程序,为什么需要进行同步实现
当多个线程更新一个对象时,没有这样的要求除了。如果线程在自己的对象上工作并且从不在线程之间共享它们,则不需要同步。如果多个线程正在更新一个对象(例如共享的StringBuffer
,则synchronized
关键字确保更改在线程之间适当发布,并且关键区域由互斥锁保护,确保只有一个线程可以在一个时间。
同样重要的是要认识到,如果线程#1 创建(例如)HashMap
,然后线程#2 想要使用该HashMap
,即使它没有更新它,那么某种同步需要碰巧在线程#1 和#2 之间适当地同步内存。
synchronization
强制执行适当的互斥锁,以便关键代码一次只有一个线程在其上工作,并确保适当的内存发布,以便线程在对象的最新版本上工作,而不是在其本地内存中可能过时的版本上工作缓存。
【讨论】:
非常感谢@Gray 对我在查询中提到的每一点进行了如此详细的解释。【参考方案3】:不应该要求如果我们不希望String同时被所有线程操作,那么我们应该使用StringBuffer,否则就可以使用StringBuilder?我想了解的是对于多线程应用程序,为什么需要进行同步实现(如果要求没有说明)。
是的。
很少有应用程序实际上同时修改一个字符序列,结果几乎没有理由使用StringBuffer
。
【讨论】:
你是对的:两个线程同时使用 StringBuilder 的“现实世界”可能性很小。同样,选择 StringBuilder 而不是 StringBuffer 的“现实世界”性能提升最多可能是“最小的”。我的强烈偏好——出于几个不同的原因——仍然是 StringBuffer :)以上是关于对于多线程应用程序,为啥需要同步实现(如果要求没有说明)的主要内容,如果未能解决你的问题,请参考以下文章