[英]Can a class with getters separate from input processing methods be considered “thread-safe”?
我正在读一本关于Java的书,有一个练习题,他们用一个私有变量声明了一个类,一个公共void
方法做了一些昂贵的操作来计算然后设置私有变量,另一个公共方法返回私人变量。 问题是“如何使这个线程安全”,一个可能的答案是“同步两个方法中的每一个”,另一个可能的答案是“这个类不能成为线程安全的”。
我认为类不能成为线程安全的,因为即使你同步这两个方法,你可能会遇到Thread1会调用setter的情况,在Thread1可以调用getter之前,Thread2可能会执行并调用setter,这样当Thread1去检索结果会得到错误的信息。 这是看待事物的正确方法吗? 书中提出的正确答案是,通过同步这两种方法可以使类成为线程安全,现在我很困惑......
我认为类不能成为线程安全的,因为即使你同步这两个方法,你可能会遇到Thread1会调用setter的情况,在Thread1可以调用getter之前,Thread2可能会执行并调用setter,这样当Thread1去检索结果会得到错误的信息。 这是看待事物的正确方法吗?
你是对的。 无法保证线程不会在类中调用每个方法之间调用任何一种方法。
如果你想这样做,那将需要一个包装类。 所以如果带有getter和setter的类是这样的:
class Foo
{
private static int bar;
public static synchronized void SetBar(int z) { ... }
public static synchronized int GetBar() { ... }
}
包装类看起来像这样:
class FooWrapper
{
public synchronized int SetGetBar(int z)
{
Foo.SetBar(z);
return Foo.GetBar();
}
}
保证这一点的唯一方法是,如果你可以保证所有的调用都将通过你的包装类,而不是直接到类Foo。
当你使这两个同步时,getter和setter本身是线程安全的。 进一步来说:
但是,使getter和setter 本身是线程安全的并不意味着应用程序作为一个整体 (即使用此类的任何东西)是线程安全的。 如果您的线程想要调用setter,那么在调用getter时获取相同的值,这涉及在不同级别上的同步。
就线程安全性而言,线程安全类不需要控制如何调用其方法(例如,它不需要控制线程交换其调用的方式),但它需要确保它们何时 ,方法做他们应该做的事。
Java中的synchronized
是一个对象范围的锁。 任何给定对象的一个synchronized
方法一次只能在任何给定的线程上执行。 让我们来上课:
class Foo
{
private int bar;
public synchronized void SetBar() { ... }
public synchronized int GetBar() { ... }
}
SetBar()
。 线程1获取对象锁。 SetBar()
,但线程1持有锁。 线程2现在排队等待线程1将释放它时获取锁定。 SetBar()
并释放锁。 SetBar()
。 GetBar()
。 线程1现在排队等待线程2将释放它时获取锁定。 SetBar()
并释放锁。 GetBar()
,并完成它。 你做了两次工作,但没有造成任何竞争条件。 两次工作可能会或可能不会是错误的,具体取决于它是什么。
一个常见的模式是让一个线程产生内容,另一个线程做一些有用的东西。 这被称为生产者 - 消费者模式。 在这种情况下,对于谁或什么尝试SetBar()
以及尝试GetBar()
内容没有混淆。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.