线程和同步

时间:2010-07-29 16:13:51

标签: java thread-safety

我在理解以下代码时遇到了问题: -

public class SoCalledSigleton{

    private final static boolean allDataLoaded = SoCalledSigleton();

    private SoCalledSigleton(){

         loadDataFromDB();
         loadDataFromFile();
         loadDataAgainFromDB();

    }    
}

这段代码线程安全吗?如果不是那么为什么?

5 个答案:

答案 0 :(得分:5)

这将在Java中产生错误。

private final static boolean allDataLoaded = SoCalledSigleton();
  • 您正在将对象分配给布尔变量。
  • 您忘记添加new来实例化变量。

但如果您的代码是这样的

 public class SoCalledSigleton{

    private final static SoCalledSigleton allDataLoaded = new SoCalledSigleton();

    private SoCalledSigleton(){

         loadDataFromDB();
         loadDataFromFile();
         loadDataAgainFromDB();

    }    
}

它是线程安全的,因为静态初始化和静态属性是线程安全的。它们只被初始化一次并存在于整个系统的整个生命周期中。

答案 1 :(得分:2)

(我认为allDataLoaded应该是SoCalledSigletonboolean只是一个错字: - )

如果类没有其他构造函数,或者loadData*方法没有做有趣的业务(例如发布this),那么它的初始化是线程安全的,因为最终静态数据成员的初始化由JVM守卫。首次加载类时,类加载器会初始化这些成员。在此期间,类上有一个锁,因此即使多个线程尝试并行访问该类,初始化过程也是线程安全的。因此,保证类的构造函数只被调用一次(每个类加载器 - 感谢Visage澄清: - )。

请注意,既然你没有向我们展示课程的其余部分(我认为它至少应该有一个static getInstance方法,可能还有其他非静态成员),我们不能说出是否整个类的实现是否是线程安全的。

答案 2 :(得分:2)

代码在当前形式下无法使用,因此线程安全的任何概念都是无关紧要的。

用户使用什么公共接口来获取单例的实例?

答案 3 :(得分:0)

是的,这是线程安全的。 “方法”是构造函数,它将在加载类时调用,即恰好一次。

但是看看正在完成的工作,我认为从类加载器调用它可能是一个糟糕的想法。从本质上讲,当代码中的某些内容触及SoCalledSingleton时,您最终会完成数据库连接和事务。有可能,这不会出现在一些明确定义的事件序列中,如果出现错误,您可以使用catch块来进行一些有用的GUI消息处理或其他任何事情。

“更干净”的方法是使用synchronized static getInstance()方法,该方法将构建您的类并在第一次调用getInstance()时准确调用其代码。

编辑:正如精英绅士所指出的,那里存在语法错误。你需要说

private final static SoCalledSingleton allDataLoaded = new SoCalledSigleton();

答案 4 :(得分:0)

从我们看到的内容,没有具体的问题 - 保证构造函数只会被调用一次(因此根据定义不能运行多线程),我认为是什么你担心的。

但是,仍有可能存在问题。首先,如果loadData...方法是公共的,那么任何人都可以随时调用它们,很可能会导致并发错误。

此外,这些方法可能会在某处修改某种类型的集合。如果在构造函数返回之前公开访问这些集合,那么您可以很容易地再次遇到并发问题。这可能是更新特定于实例的字段的任何异常的问题(静态字段可能会也可能不会出现此问题,具体取决于文件中定义的位置)。

根据类的使用方式,只需编写所有单线程数据可能都不够好。即使只读,集合类对于多线程访问也不一定安全,因此如果多个线程可能访问您的单例,则需要确保使用线程安全的数据结构。

也可能存在其他问题。线程安全不是一个简单的检查列表;您需要考虑可以同时访问哪些代码/数据,并确保采取适当的操作(声明方法synchronized,使用并发集合等)。线程安全也不是二元的东西(即本身没有“线程安全”的东西);它取决于一次访问类的线程数量,方法的哪些组合是线程安全的,操作序列是否会继续按预期运行(你可以使一个类“线程安全”,因为它不是崩溃,但某些返回值如果被抢占则是未定义的),监视线程需要保持什么以保证某些不变量等。

我想我想说的是你需要思考并理解如何使用这个类。向人们显示半个文件的快照(甚至不编译),并要求他们给出是/否答案,这不会有益。如果有的话,他们最好会为你指出一些的问题;在最坏的情况下,你会有一种虚假的自信心。