三种实现方法详解:
懒汉式
public class SingletonDemo{
private static SingletonDemo s = new SingletonDemo();private SingletonDemo(){
}
public static SingletonDemo getInstance(){
return s;
}
}
在类加载的时候得到一个实例化对象,java vm只要加载一了类以后,就不用再加载一次了,保证了实例只有一个。
public class Singleton2{
private Singleton2{
}
private static Singleton2 instance = null;
public synchonized static Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
由于是同步方法(在同一时间只能有一个线程访问,并且其他线程只有等到当前获得锁的线程执行完整个方法才能获得锁执行方法),对性能不是消耗大,能不能有更好的方法呢。实际上只需要将实例化对象的代码同步。这样就减少性能消耗。
private static SingletonDemo2 getInstance(){if(instance == null){
synchronized (SingletonDemo2.class) {
instance = new SingletonDemo2();
}
}
return instance;
}
那上面的代码有没有问题呢,问题肯定是有的。当一个线程执行到if(instance == null)语句后,有可能它的时间片到期了,轮到其他线程执行,其他线程创建了对象并执行完成释放了锁。等到第一个线程再次获得时间片,继续执行,就会造成再次创建了新对象。
这样的情况是不可预料的,时间片的轮换是由操作系统控制。我们可以通过一下的代码发现问题。
private static SingletonDemo2 getInstance() throws Exception{
if(instance == null){
Thread.sleep(10);
synchronized (SingletonDemo2.class) {
instance = new SingletonDemo2();
}
}
return instance;
}
测试代码:
public static void main(String arg []) throws Exception{
class ThreadTest extends Thread{
private SingletonDemo2 ins1;
public void run(){
ins1 = SingletonDemo2.getInstance();
System.out.println(ins1); //看对象是不是同一个,第一种方法,比较打印的内存地址。
}
public SingletonDemo2 get(){
return ins1;
}
}
ThreadTest thread1 = new ThreadTest();
ThreadTest thread2 = new ThreadTest();
thread1.start();
thread2.start();
//第二中方法,equals比较
Thread.sleep(1000);//要等两个线程,执行完成才能比较
System.out.println(thread1.get().equals(thread2.get()));
}
执行结果:
C:\Users\twolight\Desktop>java SingletonDemo4
SingletonDemo4@1034bb5
SingletonDemo4@7f5f5897
false
这个问题如何解决呢。下面代码:
private static SingletonDemo2 getInstance(){
if(instance == null){
synchronized (SingletonDemo2.class) {
if(instance== null){
instance = new SingletonDemo2();
}
}
}
return instance;
}
//懒汉模式(Double check)
class SingletonDemo2{
private static SingletonDemo2 instance;
private SingletonDemo2(){
}
private static SingletonDemo2 getInstance(){
if(instance == null){
synchronized (SingletonDemo2.class) {
if(instance == null){
instance = new SingletonDemo2();
}
}
}
return instance;
}
}
内部类实现:
class SingletonDemo3{
private SingletonDemo3(){
}
private static class Instance{
private static SingletonDemo3 s = new SingletonDemo3();
private Instance(){
}
private static SingletonDemo3 getInstance(){
return s;
}
}
private static SingletonDemo3 getInstance(){
return Instance.getInstance();
}
}
内部类的静态变量在类加载的时候初始化,所以能够保证对象的唯一性。并且只有到使用的时候才实例化对象。不是懒汉式加载的时候就实例化。