当我试图掌握线程安全时,我想知道这个类是否是线程安全的?如果两个线程在任何时候都试图访问它的变量,在我看来它是线程安全的,因为:
请告诉我,如果我错了,或者这个课程不是线程安全的。
public class MyClass{
private final String = "mystring"; //thread safe because final
private AnObject mObject;
public MyClass(){
//initialize
}
//only one class can set the object at a time.
public synchronized void setObj(AnObject a){
mObject = a;
}
//two threads trying to get the same object will not read different values.
public synchronized AnObject getObj(){
return mObject;
}
//better to synchronize the smallest possible block than the whole method, for performance.
public void changeObj(){
//just using local variables (on stack) so no need to worry about thread safety
int i = 1;
//i and j are just to simulate some local variable manipulations.
int j =3;
j+=i;
synchronized(this){
//change values is NOT synchronized. Does this matter? I don't think so.
mObject.changeValues();
}
}
}
答案 0 :(得分:6)
不,这不是线程安全的。如果使用AnObject
方法,您确保只有一个线程可以一次更改changeObj()
中的值,但是您还为此对象提供了一个getter,因此任何其他线程都可以调用{{1}并发。
答案 1 :(得分:2)
你的类本身在当前状态下是线程安全的(假设这里没有显示任何方法),但是你的思维中可能有一个“bug”;
mObject
不是100%封装的,它是通过setter传入的,可以通过getter获取。这意味着任何线程都可以同时获取对mObject引用的对象的引用和调用方法,而MyClass不知道它。
换句话说,AnObject的方法也可能需要线程安全。
至少,MyClass 中的同步不会以任何方式使mObject免于线程化问题。
答案 2 :(得分:1)
除了JB Nizet先生的观点之外,如果AnObject.changeValues
是一种旨在被客户覆盖的方法,或者调用此类方法,那么在一般情况下,这会为各种不需要的行为打开大门,像死锁和数据损坏。您绝不能将控制权交给同步块中的外来代码。 “外星人”是指不受你控制的代码。更多细节可以在Effective Java,2nd Ed,Item 67中找到。
答案 3 :(得分:1)
最终变量不一定是线程安全的,只有不可变的最终变量是线程安全的 - 它涵盖了诸如String
之类的原语和类,或者本身是线程安全的类的最终变量。
您的类不是线程安全的,因为它暴露了变量a
,但也需要它来进行内部工作。
以下示例将演示a
如何进入不一致状态的示例。
主题A
MyClass myClass = ...
myClass.changeObj();
// imagine Thread A is suspended during the synchronized block inside of
// changeObj()
Thead B
MyClass myClass = ...
AnObj anObj = myClass.getObj();
anObj.changeValues();
// uh-oh, I am modifying the state of this instance of anObj which is also
// currently being modified by Thread A
要使MyClass真正保证线程安全,您必须执行以下操作之一。