
摘自Jark博客,有人认为使用volatile的原因是可见性,这意味着它可以确保线程在本地没有实例的副本,并且每次都从主内存中读取它. 但这实际上是错误的. 使用volatile的主要原因是另一个功能: 禁止指令重新排序优化. 也就是说,在易失变量的赋值操作之后,将有一个存储屏障(在生成的汇编代码上),并且在该存储屏障之前不会对读取操作进行重新排序. 例如,在上面的示例中,必须在1-2-3或1-3-2之后执行获取操作,并且不存在执行1-3然后获得值的情况. 从“优先发生原理”的角度来看,这意味着易失性变量的写操作发生在变量的读操作之前(这里的“后退”是按时间顺序排列的).
但是请特别注意以下事实: 在Java 5之前的版本中使用易失性双重检查锁仍然存在问题. 原因是Java 5之前的JMM(Java内存模型)存在缺陷. 即使将变量声明为volatile,也无法完全避免重新排序. 主要原因是volatile变量之前和之后的代码仍然存在重新排序问题. 易失性屏蔽重新排序的问题仅在Java 5中得以解决,因此您以后可以放心使用volatile.
class Singleton{
private static final Singleton INSTANCE = new Singleton();
private Singleton(){}
public Singleton getInstance(){
return INSTANCE;
}
}

由于实例被声明为静态变量和最终变量,因此它将在第一次加载类时在内存中初始化,因此创建实例本身是线程安全的. 这也是因为对象是在类加载期间创建的,因此图像称为“饥饿的人”.
但是他的缺点也很明显,因为即使客户端未调用此方法,该类的实例也已创建,这在一定程度上也造成资源浪费. 同时,他不能在某些使用情况下使用它: 例如,实例的创建取决于参数或配置文件. 在getInstance之前写一个线程安全的单例模式,必须调用一个方法来为其设置参数,然后才能使用此单例模式.
这一次(当当当当!!),我们应该使用我们的把戏-静态内部类.
public class Singleton {
private static class SingletonCreater{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonCreater.INSTANCE;
}
}

为什么静态内部类可以实现线程安全的调用?首先看一下内部类加载的时间:
1. 调用外部类的静态变量和静态方法可以将外部类加载到内存中,但不会加载被调用外部类的内部类(无论是否为静态).
2. 在加载静态内部类之前,将首先加载外部类. 静态内部类或非静态内部类仅在使用其成员时加载.
3. 内部类可以自由使用外部类的成员对象和方法(甚至是私有的),而无需生成外部类对象

然后写一个线程安全的单例模式,当线程调用getInstance方法时,因为调用了静态内部类的成员,所以将内部类加载到内存中,并且此时也将内部类的成员加载并初始化,因此返回是外部类Too的实例. 这种编写方法仍然使用JVM自己的机制来确保线程安全. 由于SingletonHolder是私有的,因此除了getInstance()之外没有其他方法可以访问它,因此它很懒. 同时,在读取实例时它不会同步. 性能缺陷;也不依赖于JDK版本.
有没有更简单的实现?一些! ! ! !枚举!
public enum EasySingleton{
INSTANCE;
}
超级简单吗? ! ! !由于创建枚举类的实例的过程是线程安全的,因此我们可以使用EasySingleton.INSTANCE来调用该实例.

顺便说一句,回顾一下枚举
枚举格式:
//只有枚举项的枚举类
public enum 枚举类名 {
枚举项1,枚举项2,枚举项3…;
}
这里的每个枚举项都是枚举类的实例,或者您可以编写带有参数的枚举类型:
public enum 枚举类名 {
枚举项1("100-90"),枚举项2("90-80"),举项3("80-70")...;
String value;
枚举类名(String str){ //构造方法
this.value = str;
}
}
使用抽象方法进行枚举: 创建枚举对象时实现抽象方法
public enum 枚举类名 {
枚举项1("100-90"){
public String localValue(){
return "优秀";
}
},枚举项2("90-80"){
...
},枚举项3("80-70"){
...
};
String value;
枚举类名(String str){ //构造方法
this.value = str;
}
public abstract String localValue();
}
有关枚举的更多知识: 单击此处
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-276998-1.html
本来自己就不在理
赚了
物价也将更便宜
起床了吗