java 单例模式
单例模式有以下特点:
1.单例类只能有一个实例(该类只能有一个实例)
2.单例类必须自己创建实例
3.单例类必须给所有其他对象提供这一实例
计算机系统中,如线程池、缓存、日志对象、驱动程序等被设置成单例。在多线程环境下,可能有一些同步问题。
如下代码所示:
public class TestStream {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//该类只能有一个实例
private TestStream(){} //私有无参构造方法
//该类必须自行创建
//有2种方式
/*private static final TestStream ts=new TestStream();*/
private static TestStream ts1=null;//懒汉单例模式
//这个类必须自动向整个系统提供这个实例对象
public static TestStream getTest(){//这里用的是懒汉单例模式
if(ts1==null){
ts1=new TestStream();
}
return ts1;
}
public void getInfo(){
System.out.println("output message "+name);
}
}
public class TestMain {
public static void main(String [] args){
TestStream s=TestStream.getTest();
s.setName("张孝祥");
System.out.println(s.getName());
TestStream s1=TestStream.getTest();
s1.setName("张孝祥");
System.out.println(s1.getName());
s.getInfo();
s1.getInfo();
if(s==s1){
System.out.println("创建的是同一个实例");
}else if(s!=s1){
System.out.println("创建的不是同一个实例");
}else{
System.out.println("application error");
}
}
}
运行结果:
张孝祥
张孝祥
output message 张孝祥
output message 张孝祥
创建的是同一个实例
懒汉单例模式:默认不自动实例化,等用的时候根据当前情况实例化
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null)
return new Singleton();
else
return instance;
}
}
饿汉单例模式:在类第一次加载的时候强制实例化
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
单例模式的线程同步问题:
两个线程,一个发现变量是null,准备创建变量,第二个也发现变量是null,创建变量,就会造成在一个JVM中有多个单例类型的实例。
解决线程安全的方案:
1.使用synchronized方法对getInstance()方法进行同步
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public synchronized static Singleton getInstance(){
if(instance == null) //mark1
return new Singleton();//mark2
else
return instance;
}
}
2.双重锁
但是用synchoronized会导致性能下降,我们想要的只是mark1和mark2的同步,所以可以不把synchronized加在方法上,而是加在代码块里
public class Singleton{
private static volatile Singleton instance;
private static Singleton(){}
public static Singleton getSingleton(){
if(instance == null){//mark1
synchronized(Singleton.class){
if(instance == null)//mark2
return new Singleton();
return instance;
}
return instance;
}
}
}
这里用了两个判断,原因:如果两个线程同时到达mark1处,synchronized可以保证线程不同时进行,但两个线程会一个个执行,所以还要在synchronized代码块中再次判断,防止创建两个。
这个也叫作双重锁。
3.使用静态内部类
这种方法拥有单例、延迟创建(参见饿汉模式)和线程同步的优点,利用静态内部类来实现
public class Singleton{
private static Singleton(){}
private static class Lazyholder{
private static final Singleton instance = new Singleton();
}
public static Singleton getSingleton(){
return Lazyholder.instance;
}
}
当类被加载时,由于没有static代码,所以不会有操作。当第一次执行getSingleton()方法时,内部静态类会被加载,创建外部单例类实例,在内部类加载过程中,静态类只会被加载一次,static属性和static初始化块的执行是串行的,这就保证了不会有两个线程同时new Singleton()