来源:www.bjsxt.com
1.饿汉式:
package singleton;
public class Demo01 {
private static Demo01 d=new Demo01();
private Demo01(){
}
public static Demo01 getInstance(){
return d;
}
}
2.懒汉式:
package singleton;
import java.io.ObjectStreamException;
import java.io.Serializable;
public class Demo02 implements Serializable {
private static Demo02 d;
private Demo02(){
if(d!=null){
throw new RuntimeException();
}
}
public static synchronized Demo02 getInstance(){
if(null==d){
d=new Demo02();
}
return d;
}
private Object readResolve() throws ObjectStreamException{
return d;
}
}
3.双重检查锁:
package singleton;
public class Demo03 {
private static Demo03 instance = null;
public static Demo03 getInstance() {
if (instance == null) {
Demo03 sc;
synchronized (Demo03.class) {
sc = instance;
if (sc == null) {
synchronized (Demo03.class) {
if(sc == null) {
sc = new Demo03();
}
}
instance = sc;
}
}
}
return instance;
}
private Demo03() {
}
}
4.静态内部类:
package singleton;
public class Demo04 {
private static class SingletonDemo04{
private static Demo04 d=new Demo04();
}
private Demo04(){
}
public static Demo04 getInstance(){
return SingletonDemo04.d;
}
}
5.枚举:
package singleton;
public enum Demo05 {
INSTANCE;
}
单例模式并不是真正意义上的单例,某些情况下就不是单例了,比如:反射和反序列化
反射演示:
package singleton;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
Demo02 s1 = Demo02.getInstance();
Demo02 s2 = Demo02.getInstance();
System.out.println(s1);
System.out.println(s2);
Class.forName("singleton.Demo02");
/**
* 单例模式反射漏洞測試
*/
Class<?> clazz = Class.forName("singleton.Demo02");
Constructor<Demo02> c = (Constructor<Demo02>) clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Demo02 s3 = c.newInstance();
Demo02 s4 = c.newInstance();
System.out.println(s3);
System.out.println(s4);
}
}
运行结果:(发现并不是同一个对象)
解决办法:(在构造方法加上判断是不是为空,不等于空就抛出异常就避免了问题)
反序列化演示:
package singleton;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
Demo02 s1 = Demo02.getInstance();
Demo02 s2 = Demo02.getInstance();
System.out.println(s1);
System.out.println(s2);
Class.forName("singleton.Demo02");
/**
* 单例模式反射漏洞測試
*/
/* Class<?> clazz = Class.forName("singleton.Demo02");
Constructor<Demo02> c = (Constructor<Demo02>) clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Demo02 s3 = c.newInstance();
Demo02 s4 = c.newInstance();
System.out.println(s3);
System.out.println(s4);*/
/**
* 单例模式反序列化漏洞测试
*/
FileOutputStream fos = new FileOutputStream("d:/a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.close();
fos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));
Demo02 s3 = (Demo02) ois.readObject();
System.out.println(s3);
}
}
运行结果:
解决办法:(反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象)
同时可以测试这五种效率:(一个一个测试看输出耗时)
package singleton;
import java.util.concurrent.CountDownLatch;
public class Test2 {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
int threadNum = 10;
final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
for(int i=0;i<threadNum;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<1000000;i++){
Object o1 = Demo01.getInstance();
/*Object o2 = Demo02.getInstance();
Object o3 = Demo03.getInstance();
Object o4 = Demo04.getInstance();
Object o5 = Demo05.INSTANCE;*/
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await(); //main线程阻塞,直到计数器变为0,才会继续往下执行!
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
}
}
优缺点选用问题: