简体   繁体   English

线程与同步

[英]Threads and synchronisation

I've problem understanding the following piece of code:- 我在理解以下代码时遇到问题:

public class SoCalledSigleton{

    private final static boolean allDataLoaded = SoCalledSigleton();

    private SoCalledSigleton(){

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

    }    
}

Is this piece of code thread safe? 这段代码线程安全吗? If not then Why? 如果没有,那为什么呢?

This will create an error in Java. 这将在Java中创建一个错误。

private final static boolean allDataLoaded = SoCalledSigleton();
  • You're assigning an object to a boolean variable. 您正在将对象分配给布尔变量。
  • You forgot to add new to instantiate the variable. 您忘记添加new的实例化变量。

But if your code is like this 但是如果你的代码是这样的

 public class SoCalledSigleton{

    private final static SoCalledSigleton allDataLoaded = new SoCalledSigleton();

    private SoCalledSigleton(){

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

    }    
}

It is thread-safe as static initialization and static attributes are thread-safe. 它是线程安全的,因为静态初始化和静态属性是线程安全的。 They are initialized only once and exists throughout the whole life-cycle of the system. 它们仅初始化一次,并且存在于系统的整个生命周期中。

(I assume that allDataLoaded is meant to be a SoCalledSigleton and boolean is just a typo :-) (我假设allDataLoaded旨在成为SoCalledSigletonboolean只是一个错字:-)

If the class has no other constructors, or the loadData* methods don't do funny business (such as publishing this ), its initialization is thread safe, because the initialization of final static data members is guarded by the JVM. 如果该类没有其他构造函数,或者loadData*方法不做任何事情(例如发布this ),则其初始化是线程安全的,因为最终静态数据成员的初始化受JVM保护。 Such members are initialized by the class loader when the class is first loaded. 此类成员在首次加载类时由类加载器初始化。 During this, there is a lock on the class so the initialization process is thread safe even if multiple threads try to access the class in parallel. 在此期间,类上有一个锁,因此即使多个线程尝试并行访问该类,初始化过程也是线程安全的。 So the constructor of the class is guaranteed to be called only once (per classloader - thanks Visage for the clarification :-). 因此,该类的构造函数保证只能被调用一次(每个类加载器-感谢Visage的澄清:-)。

Note that since you don't show us the rest of the class (I suppose it should have at least a static getInstance method, and probably further nonstatic members), we can't say anything about whether the whole implementation of the class is thread safe or not. 请注意,由于您没有向我们展示该类的其余部分(我想它应该至少具有一个static getInstance方法,并且可能还有其他的非静态成员),因此我们无法对类的整个实现是否是线程一事无成安全与否。

The code is unusable in its current form, so any notions of thread safety are irrelevent. 该代码无法以当前形式使用,因此任何线程安全性概念都是无关紧要的。

What public interface would users use to get an instance of the singleton? 用户将使用什么公共接口来获取单例的实例?

Yeah, it's thread safe. 是的,它是线程安全的。 The "method" is the constructor, and it will be called when the class is loaded, ie exactly once. “方法”是构造函数,将在加载类时调用,即恰好一次。

But looking at the stuff being done, I think it's probably a lousy idea to call it from the class loader. 但是从完成的工作来看,我认为从类加载器中调用它可能是一个糟糕的主意。 Essentially, you'll end up doing your DB connection and stuff at the point in time when something in your code touches the SoCalledSingleton . 本质上,当代码中的SoCalledSingleton触及SoCalledSingleton时,您最终将完成数据库连接和SoCalledSingleton Chances are, this will not be inside some well-defined sequence of events where, if there's an error you have catch blocks to take you to some helpful GUI message handling or whatever. 很有可能,这不会出现在一些定义明确的事件序列中,在这些事件序列中,如果发生错误,您会使用catch块来进行一些有用的GUI消息处理或其他操作。

The "cleaner" way is to use a synchronized static getInstance() method, which will construct your class and call its code exactly when getInstance() is called the first time. “更干净”的方法是使用synchronized static getInstance()方法,该方法将构造您的类并在首次调用getInstance()时准确地调用其代码。

EDIT: As The Elite Gentleman pointed out, there's a syntax error in there. 编辑:正如精英绅士指出的那样,那里存在语法错误。 You need to say 你要说

private final static SoCalledSingleton allDataLoaded = new SoCalledSigleton();

From what we can see , there are no specific issues - it's guaranteed that the constructor will only ever by called once (so by definition can't be run multithreaded), which I presume is what you were concerned about. 从我们看到的内容来看 ,没有特定的问题-可以保证构造函数只会被调用一次(因此,根据定义,它不能运行多线程),我想这就是您所关心的。

However, there are still possible areas for problems. 但是,仍有可能出现问题。 Firstly, if the loadData... methods are public, then they can be called by anyone at any time, and quite possibly could lead to concurrency errors. 首先,如果loadData...方法是公共的,那么任何人都可以随时调用它们,并且很可能会导致并发错误。

Additionally, these methods are presumably modifying some kind of collection somewhere. 另外,这些方法大概是在某处修改某种集合。 If these collections are publically accessible before the constructor returns, then you can quite easily run into concurrency issues again. 如果在构造函数返回之前可以公开访问这些集合,那么您很容易再次遇到并发问题。 This could be an issue with anything exception updating instance-specific fields (static fields may or may not exhibit this problem depending where they are defined in the file). 更新实例特定字段的任何异常都可能是一个问题(静态字段可能会也可能不会出现此问题,具体取决于它们在文件中的定义位置)。

Depending on the way the class is used, simply writing all of the data single-threaded may not be good enough. 根据类的使用方式,仅编写所有单线程数据可能不够好。 Collection classes are not necessarily safe for multi-threaded access even if read-only, so you'll need to ensure you're using the thread-safe data structures if multiple threads might access your singleton. 集合类对于多线程访问不一定是安全的,即使它是只读的,因此如果多个线程可能会访问您的单例,则需要确保使用的是线程安全的数据结构。

There are possibly other issues too. 可能还有其他问题。 Thread-safety isn't a simple check-list; 线程安全性不是一个简单的清单。 you need to think about what bits of code/data might be accessed concurrently, and ensure that appropriate action is taken (declaring methods synchronized , using concurrent collections, etc.). 您需要考虑可能同时访问哪些代码/数据位,并确保采取了适当的措施(声明方法synchronized ,使用并发集合等)。 Thread-safety also isn't a binary thing (ie there's no such thing as "thread safe" per se); 线程安全也不是二进制的东西(也就是说,本质上没有“线程安全”之类的东西)。 it depends how many threads will be accessing the class at once, what combinations of methods are thread-safe, whether sequences of operations will continue to function as one would expect (you can make a class "thread safe" in that is doesn't crash, but certain return values are undefined if pre-empted), what monitors threads need to hold to guarantee certain invariants etc. 这取决于有多少线程将同时访问该类,哪些方法组合是线程安全的,操作序列是否将继续按预期运行(您可以使类“线程安全”,因为它不会崩溃,但某些返回值如果被抢占则未定义),监视线程需要保持什么以保证某些不变性等。

I guess what I'm trying to say is that you need to think about and understand how the class is used. 我想我想说的是,您需要考虑并理解如何使用该类。 Showing people a snapshot of half a file (which doesn't even compile), and asking them to give a yes/no answer, is not going to be beneficial. 向人们显示一个文件一半的快照(甚至无法编译),并要求他们给出是/否的答案,将不会有好处。 At best they'll point out some of the issues for you if there are any; 充其量,如果有的话 ,他们会为您指出一些问题。 at worst you'll get a false sense of confidence. 最糟糕的是,您会得到错误的信心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM