java 单例 同步_Java单例和同步

是的,这是必要的。 有几种方法可以用来通过延迟初始化来实现线程安全:

恶魔同步:

private static YourObject instance; public static synchronized YourObject getInstance() { if (instance == null) { instance = new YourObject(); } return instance; }

这个解决scheme要求每个线程在实际上只有前几个需要时才能被同步。

仔细检查同步 :

private static final Object lock = new Object(); private static volatile YourObject instance; public static YourObject getInstance() { YourObject r = instance; if (r == null) { synchronized (lock) { // While we were waiting for the lock, another r = instance; // thread may have instantiated the object. if (r == null) { r = new YourObject(); instance = r; } } } return r; }

这个解决scheme确保只有前几个尝试获取你的单例的线程必须经过获取锁的过程。

按需初始化 :

private static class InstanceHolder { private static final YourObject instance = new YourObject(); } public static YourObject getInstance() { return InstanceHolder.instance; }

该解决scheme利用Java内存模型对类初始化的保证来确保线程安全。 每个类只能加载一次,只有在需要时才加载。 这意味着,第一次调用getInstance , InstanceHolder将被加载, instance将被创build,并且由ClassLoader控制,所以不需要额外的同步。

这种模式在没有显式同步的情况下进行线程安全的实例延迟初始化!

public class MySingleton { private static class Loader { static final MySingleton INSTANCE = new MySingleton(); } private MySingleton () {} public static MySingleton getInstance() { return Loader.INSTANCE; } }

它的工作原理是它使用类加载器为您免费进行所有同步: MySingleton.Loader类首先在getInstance()方法内部访问,所以Loader类在第一次调用getInstance()时加载。 此外,类加载器保证所有的静态初始化在你访问类之前完成 – 这就是你的线程安全。

这就像魔术一样。

它实际上与Jhurtado的枚举模式非常相似,但我发现枚举模式滥用枚举概念(虽然它工作)

如果您正在使用Java的multithreading环境,并且需要保证所有这些线程正在访问一个类的单个实例,则可以使用Enum。 这将有助于您处理序列化的附加优势。

public enum Singleton { SINGLE; public void myMethod(){ } }

然后让你的线程使用你的实例:

Singleton.SINGLE.myMethod();

是的,你需要使getInstance()同步。 如果不是,那么可能会出现这样的情况,即可以制作多个class级的实例。

考虑一下你有两个线程同时调用getInstance() 。 现在想象一下T1执行刚刚过去的instance == null检查,然后T2运行。 此时实例未被创build或设置,因此T2将通过检查并创build实例。 现在想象执行切换回T1。 现在单身人士被创build,但T1已经做了检查! 它会继续做对象! 使getInstance()同步可以防止这个问题。

有几种方法可以让单例是线程安全的,但是让getInstance()同步可能是最简单的。

枚举单例

实现一个线程安全的单例最简单的方法是使用Enum

public enum SingletonEnum { INSTANCE; public void doSomething(){ System.out.println("This is a singleton"); } }

自从Java 1.5引入了Enum以来,这个代码就起作用了

双重检查locking

如果你想编写一个在multithreading环境下工作的“经典”单例(从Java 1.5开始),你应该使用这个。

public class Singleton { private static volatile Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class){ if (instance == null) { instance = new Singleton(); } } } return instance ; } }

这在1.5之前不是线程安全的,因为volatile关键字的实现是不同的。

早期加载Singleton(甚至在Java 1.5之前工作)

这个实现在类加载时实例化单例,并提供线程安全性。

public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } public void doSomething(){ System.out.println("This is a singleton"); } }

您还可以使用静态代码块在类加载时实例化实例,并防止线程同步问题。

public class MySingleton { private static final MySingleton instance; static { instance = new MySingleton(); } private MySingleton() { } public static MySingleton getInstance() { return instance; } }

在multithreading环境下,用Java实现Singleton的最好方法是什么?

参考这篇文章,了解实现Singleton的最佳方法。

什么是在Java中实现单例模式的有效方法?

当多个线程同时尝试访问getInstance()方法时会发生什么情况?

这取决于你实现方法的方式。如果你使用不带volatilevariables的双锁,你可能会得到部分构造的Singleton对象。

有关更多详细信息,请参阅此问题:

为什么在这个双重检查locking的例子中使用了volatile

我们可以让singleton的getInstance()同步吗?

真的需要同步,当使用Singleton类?

如果以下面的方式实现Singleton,则不需要

静态的投资

枚举

具有Initialization-on-demand_holder_idiom的LazyInitalaization

详情请参阅此问题

Java Singletondevise模式:问题

public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis () {...} }

来源:有效的Java – >项目2

它build议使用它,如果你确定这个类将永远保持单身。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值