第一种写法: 懒汉式单例
class Singleton{
private static Singleton singleleton=null;
pulic static Singleton getInstance(){
if(singleleton==null){
singleleton=new Singleton()
}
return singleleton;
}
private Singleton(){
singleleton=new Singleton();
}
}
特点:这种写法是线程不安全的,他无法保证同时不被多个线程访问,适合在单线程环境下使用。
要想保证线程安全,可以参考下面三种写法:
1)使用synchronized关键字
class Singleton{
private static Singleton singleleton=null;
pulic static synchronized Singleton getInstance(){
if(singleleton==null){
singleleton=new Singleton()
}
return singleleton;
}
private Singleton(){
singleleton=new Singleton();
}
}
特点:相比上个方法,在静态方法前多加了个synchronized关键字,使同一时间只能有一个线程访问该代码块。
2)双重检查锁定
class Singleton{
private static Singleton singleleton=null;
pulic static Singleton getInstance(){
if(singleleton==null){
synchronized(Singleton.class){
if(singleleton==null){
singleleton=new Singleton();
}
}
}
return singleleton;
}
private Singleton(){
singleleton=new Singleton();
}
}
特点:经过两次判定,第一次检测到实例为空时,增加同步,同步后再次检测到实例为空时,才创建对象实例。有效防止了在多线程环境下创建多个实例的问题。
3)静态内部类实现
class Singleton{
private singleton(){}
private static class SingleBuilder{
private static Singleton singleton=new Singleton(); //就像private int int=1
}
public static Singleton getInstance(){
return SingleBuilder.singleton;
}
}
特点:Java中静态内部类可以访问其外部类的成员属性和方法,同时java规定静态内部类只在首次调用时被加载,因此实现了懒汉式,所以他只被加载一次,所以是线程安全的
2.饿汉式:
class Singleton{
private static Singleton singleleton=new Singleton();
pulic static Singleton getInstance(){
return singleleton;
}
private Singleton(){}
}
特点:饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。
3.登记式:
public class Singleton {
private static Map< String,Singleton> map = new HashMap< String,Singleton>();
static{
Singleton single = new Singleton();
map.put(single.getClass().getName(), single);
}
//保护的默认构造子
protected Singleton(){}
//静态工厂方法,返还此类惟一的实例
public static Singleton getInstance(String name) {
if(name == null) {
name = Singleton.class.getName();
System.out.println("name == null"+"--->name="+name);
}
if(map.get(name) == null) {
try {
map.put(name, (Singleton) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
}
public static void main(String[] args) {
Singleton3 single = Singleton.getInstance(null);
}
}
登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。 内部实现还是用的饿汉式单例。
4.使用volatile 关键字
class Singleton{
private static volatile Singleton Instance=null;
public Singleton() {
}
public static Singleton getInstance(){
if(Instance==null){
synchronized (Singleton.class) {
if (Instance == null) {
Instance = new Singleton();
}
}
}
return Instance;
}
}
volatile 保证在实例对象创建后快速通知其他线程该对象的实例已经存在,不需要重复创建了。
转载请注明原文地址: https://ju.6miu.com/read-1201766.html