Ric*_*vis 109 java singleton multithreading synchronization
请澄清我对Singleton和Multithreading的疑问:
getInstance()
方法时会发生什么?getInstance() synchronized吗?Jef*_*rey 201
是的,这是必要的.使用延迟初始化可以使用多种方法来实现线程安全:
严厉同步:
private static YourObject instance;
public static synchronized YourObject getInstance() {
if (instance == null) {
instance = new YourObject();
}
return instance;
}
Run Code Online (Sandbox Code Playgroud)
该解决方案要求每个线程同步,而实际上只需要前几个.
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;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案确保只有尝试获取单例的前几个线程必须经历获取锁定的过程.
private static class InstanceHolder {
private static final YourObject instance = new YourObject();
}
public static YourObject getInstance() {
return InstanceHolder.instance;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案利用Java内存模型保证类初始化以确保线程安全.每个类只能加载一次,只有在需要时才会加载.这意味着第一次getInstance被调用,InstanceHolder将被加载instance并将被创建,并且由于这是由ClassLoaders 控制的,因此不需要额外的同步.
Boh*_*ian 65
此模式在没有显式同步的情况下对实例执行线程安全的延迟初始化!
public class MySingleton {
private static class Loader {
static final MySingleton INSTANCE = new MySingleton();
}
private MySingleton () {}
public static MySingleton getInstance() {
return Loader.INSTANCE;
}
}
Run Code Online (Sandbox Code Playgroud)
它的工作原理是因为它使用类加载器为您免费执行所有同步:MySingleton.Loader首先在getInstance()方法内部访问Loader该类,因此该类getInstance()在第一次调用时加载.此外,类加载器保证在您访问类之前完成所有静态初始化 - 这就是为您提供线程安全性的方法.
这就像魔术一样.
它实际上非常类似于Jhurtado的枚举模式,但我发现enum模式滥用了enum概念(尽管它确实有效)
jhu*_*ado 21
如果您正在使用Java中的多线程环境并且需要保证所有这些线程都在访问类的单个实例,则可以使用Enum.这将有助于您处理序列化的附加优势.
public enum Singleton {
SINGLE;
public void myMethod(){
}
}
Run Code Online (Sandbox Code Playgroud)
然后让你的线程使用你的实例,如:
Singleton.SINGLE.myMethod();
Run Code Online (Sandbox Code Playgroud)
是的,你需要进行getInstance()同步.如果不是,可能会出现可以制作类的多个实例的情况.
考虑你有两个同时调用的线程的情况getInstance().现在假设T1刚刚执行instance == null检查,然后T2运行.此时,实例未创建或设置,因此T2将通过检查并创建实例.现在假设执行切换回T1.现在创建了单例,但是T1已经完成了检查!它将继续制作该对象!制作getInstance()同步防止这个问题.
有几种方法可以使单例线程安全,但是getInstance()同步可能是最简单的.
Enum singleton
实现线程安全的Singleton的最简单方法是使用Enum
public enum SingletonEnum {
INSTANCE;
public void doSomething(){
System.out.println("This is a singleton");
}
}
Run Code Online (Sandbox Code Playgroud)
自从Java 1.5中引入Enum以来,此代码就可以运行了
双重检查锁定
如果你想编写一个在多线程环境中工作的"经典"单例(从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 ;
}
}
Run Code Online (Sandbox Code Playgroud)
这在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");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
103732 次 |
| 最近记录: |