线程同步 线程安全
您知道什么是线程安全吗? 如果没有,下面是一个简单的示例。 所有类都必须是线程安全的,对吗? 并不是的。 其中一些必须是线程安全的? 又错了。 我认为它们都不必是线程安全的,而它们都必须提供同步的装饰器。
让我们从一个示例开始(顺便说一下,它是mutable ):
class Position {private int number = 0;@Overridepublic void increment() {int before = this.number;int after = before + 1;this.number = after;}
}
您如何看待-它是线程安全的吗? 该术语指的是当同时由多个线程使用时,此类的对象是否将正确运行。 假设我们有两个线程在同一个对象position
,并在完全相同的时刻调用其方法increment()
。
我们期望两个线程结束时整数的number
等于2,因为它们每个都会递增一次,对吗? 但是,这极有可能不会发生。
让我们看看会发生什么。 在两个线程中,启动时, before
等于0
。 然后after
将设置为1
。 然后,两个线程会做this.number = 1
,我们将结束与1
的number
,而不是预期2
。 看到问题了吗? 在设计中存在此类缺陷的类不是线程安全的 。
最简单,最明显的解决方案是使我们的方法synchronized
。 这样可以保证无论有多少线程同时调用它,它们都会按顺序而不是并行进行:一个线程接一个线程。 当然,这将花费更长的时间,但是它将防止该错误的发生:
class Position {private int number = 0;@Overridepublic synchronized void increment() {int before = this.number;int after = before + 1;this.number = after;}
}
保证无论有多少线程都不会中断的类称为线程安全 。
现在的问题是:我们是否必须使所有类都成为线程安全的,或者只使其中某些类成为线程安全的? 使所有类都无错误似乎更好,对吗? 为什么有人想要一个可能在某个时候破裂的物体? 好吧,不完全是。 请记住,涉及性能问题; 我们通常没有多个线程,并且我们始终希望我们的对象尽可能快地运行。 线程间同步机制肯定会使我们慢下来。
我认为正确的方法是开设两个班级。 第一个不是线程安全的,而另一个是同步的decorator ,它看起来像这样:
class SyncPosition implements Position {private final Position origin;SyncPosition(Position pos) {this.origin = pos;}@Overridepublic synchronized void increment() {this.origin.increment();}
}
现在,当我们需要position
对象是线程安全的时,我们可以使用SyncPosition
装饰它:
Position position = new SyncPosition(new SimplePosition()
);
当我们需要一个简单的简单位置而没有任何线程安全性时,我们可以这样做:
Position position = new SimplePosition();
我认为使类功能既丰富又线程安全是违反了那个著名的单一责任原则的 。
顺便说一句,这个问题非常接近防御性编程和验证程序之一。
您可能还会发现与这些相关的帖子有趣: 您如何使用InterruptedException? ; 为什么InputStream设计错误 ; 限制Java方法执行时间 ; 如何实现一个迭代适配器 ; 通过验证装饰器进行防御性编程 ;
翻译自: https://www.javacodegeeks.com/2017/01/synchronized-decorators-replace-thread-safe-classes.html
线程同步 线程安全