正如我们在创建单顿类同步操作时所知道的,我们将整个方法作为同步或仅是负责创建对象同步的语句的块。但是,在这两种方法中,更好,为什么?
方法1
public static A getA(){
if (obj == null){
synchronized(Singleton.class) {
if (obj == null) {
obj = new Singleton();//instance will be created at request time
}
}
}
return obj;
}
方法2
public synchronized static A getA(){
if (obj == null){
obj = new Singleton();//instance will be created at request time
}
return obj;
}
概念:
public synchronized static A getA(){
if (obj == null){
obj = new Singleton();//instance will be created at request time
}
return obj;
}
在方法上使用同步关键字(如上面的示例)同步对整个方法的访问,这通常是很安全的,但是除非您有很小的方法,否则您可能会同步一块代码,而不是绝对需要的代码。到,这更多的是性能。因为一次只能通过一个线程访问同步块/方法,所以它们确实会减慢处理。您同步的一大块代码越大,性能命中率就越好。
如果您仅需要一个懒惰的单个资源,则需要做类似的事情:
class MyClass {
private static volatile Resource resource;
private static final Object LOCK = new Object();
public static Resource getInstance() {
if(resource == null) {
synchronized(LOCK) { // Add a synch block
if(resource == null) { // verify some other synch block didn't
// write a resource yet...
resource = new Resource();
}
}
}
return resource;
}
}
这里重要的是volatile
修饰符,为应用程序中的整个线程提供可见性。
第一个更好,因为当obj
不为null时,您不会获得锁,而第二种方法每次都会获取锁。
我会拿第一个,它具有双检查锁定。
也许您也可以尝试这样的事情:
public class MySingleton {
private static instance = new MySingleton ();
private MySingleton (){ }
public MySingleton getInstance {
return instance;
}
}
您最好使用"持有人成语"
public class HolderFactory {
public static Singleton get() {
return Holder.instance;
}
private static class Holder {
public static final Singleton instance = new Singleton();
}
}
这很懒惰,因为将在第一次调用get()
时创建实例,并且它是线程安全的,因为类别可以通过classloader加载单个线程中的类。您也可以检查此链接以获取有关单元和线程安全的更多详细信息:https://shipilev.net/blog/2014/saf-public-construction/