java代码:
package com.bjsxt.singleton;
import java.util.concurrent.CountDownLatch;
/**
* 多线程测试 饿汉式、懒汉式、静态内部类式、枚举式调用效率
*/
public class Client4 {
public static void main(String[] args) throws Exception {
int threadNum = 10;
int times = 1000000;
System.out.println("=============="+threadNum+"个线程,每个线程调用获取对象的公共方法 "+times+"次");
testSingleton(threadNum,times,"饿汉式");
testSingleton(threadNum,times,"懒汉式");
testSingleton(threadNum,times,"静态内部类式");
testSingleton(threadNum,times,"枚举式");
}
private static void testSingleton(int threadNum, int times, String type) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(threadNum);
long start = System.currentTimeMillis();
for(int i=0;i<threadNum;i++){
new Thread(()->{
if("饿汉式".equals(type)){
for(int j = 0;j<times;j++){
Singleton1 singleton1 = Singleton1.getInstance();
}
}else if("懒汉式".equals(type)){
try {
for(int j = 0;j<times;j++){
Singleton6 singleton6 = Singleton6.getInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
}else if("枚举式".equals(type)){
for(int j = 0;j<times;j++){
Singleton5 singleton5 = Singleton5.INSTANCE;
}
}else if("静态内部类式".equals(type)){
for(int j = 0;j<times;j++){
Singleton4 singleton4 = Singleton4.getInstance();
}
}
countDownLatch.countDown();
},"thread-"+i).start();
}
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println(type+" cost "+(end - start) +"ms");
}
}
package com.bjsxt.singleton;
/**
* 饿汉式
*/
public class Singleton1 {
// 类加载过程线程安全。类加载时,就创建对象到堆里,不具备延时加载
private static Singleton1 instance = new Singleton1();
private Singleton1(){
}
// 调用效率高
public static Singleton1 getInstance(){
return instance;
}
}
package com.bjsxt.singleton;
import java.io.Serializable;
/**
* 懒汉式
*/
public class Singleton2 implements Serializable {
int age=0;
private static Singleton2 instance;
private Singleton2(){
}
// 有 synchronized 调用效率低。线程安全。使用时才会创建对象,延时加载。
public static synchronized Singleton2 getInstance(){
if(instance == null){
instance = new Singleton2();
}
return instance;
}
}
package com.bjsxt.singleton;
/**
* 静态内部类
*/
public class Singleton4 {
// 类加载时不会加载静态内部类,调用getInstance是加载内部类,创建对象,所以是延时加载。又类初始化是线程安全,所以线程安全。
private static class InnerClassSigleton4{
private static Singleton4 instance = new Singleton4();
}
private Singleton4(){
}
// 没有synchornized 所以调用效率高
public static Singleton4 getInstance(){
return InnerClassSigleton4.instance;
}
}
package com.bjsxt.singleton;
/**
* 枚举方式
*/
public enum Singleton5 {
INSTANCE;
// 调用效率高,线程安全,不能延时加载。是利用jvm底层,所以避免了反射反序列导致的一个类有多个实力的漏洞。
public void operateInstance(){
}
}
package com.bjsxt.singleton;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* 懒汉模式:防止反序列化,反射破解
*/
public class Singleton6 implements Serializable {
private static Singleton6 instance;
private Singleton6() throws Exception {
// 应对反射破解单利
if(instance!=null){
throw new Exception("对象已存在,禁止创建!");
}
}
public static synchronized Singleton6 getInstance() throws Exception {
if(instance ==null){
instance = new Singleton6();
}
return instance;
}
// 反序列化会回调这个方法,方法返回指定对象
private Object readResolve() throws ObjectStreamException {
return instance;
}
}
运行结果:
总结:
静态内部类延时加载、线程安全、调用效率高。
懒汉式延时加载、线程安全、调用效率低(3位数,其他都是两位数)
饿汉式无延时加载、线程安全、调用效率高
枚举式无延时加载、线程安全、调用效率高,而且天然不存在反射、反序列化破解问题,其他模式存在这个问题,需要修改代码补救。从这个角度说,当对象创建需要时空小时,枚举式优于饿汉式。
当对象创建需要时空大时,静态内部类调用时间比懒汉式时间第一个量级,静态内部类优于懒汉式。