单例模式在实际应用中使用非常广泛,比如日志写入,单例模式可以避免错误,数据库连接可以避免锁死,用例执行可以避免重复调用。
先是枚举实现法:
public enum Singleton01 {
INSTANCE;
public void operator() {
System.out.println("Operator");
}
}
再是内部类实现法:
public class Singleton02 {
private static class Module {
private static final Singleton02 instance = new Singleton02();
}
private Singleton02() {
;
}
public static Singleton02 getInstance() {
return Module.instance;
}
}
再是饿汉式:
public class Singleton03 {
private static final Singleton03 instance = new Singleton03();
private Singleton03() {
}
public static Singleton03 getInstance() {
return instance;
}
}
再是懒汉式:
public class Singleton04 {
private static Singleton04 instance;
private Singleton04() {
}
public synchronized static Singleton04 getInstance() {
if (instance == null) {
instance = new Singleton04();
}
return instance;
}
}
下面是测试程序:
import java.util.concurrent.CountDownLatch;
public class Client2 {
private static int threadCount = 10;
private static long jobCountPerThread = 1000000L;
public static void main(String[] args) throws InterruptedException {
testEnum();
testInnerClass();
testHungeryClass();
testLazyClass();
}
public static void testEnum() throws InterruptedException {
long startTime = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < jobCountPerThread; i++) {
Singleton01 s1 = Singleton01.INSTANCE;
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
long endTime = System.currentTimeMillis();
System.out.println("枚举单例模式总消耗时间:" + (endTime - startTime) + "毫秒");
}
public static void testInnerClass() throws InterruptedException {
long startTime = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < jobCountPerThread; i++) {
Singleton02 s1 = Singleton02.getInstance();
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
long endTime = System.currentTimeMillis();
System.out.println("内部类单例模式总消耗时间:" + (endTime - startTime) + "毫秒");
}
public static void testHungeryClass() throws InterruptedException {
long startTime = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < jobCountPerThread; i++) {
Singleton03 s1 = Singleton03.getInstance();
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
long endTime = System.currentTimeMillis();
System.out.println("饿汉式单例模式总消耗时间:" + (endTime - startTime) + "毫秒");
}
public static void testLazyClass() throws InterruptedException {
long startTime = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < jobCountPerThread; i++) {
Singleton04 s1 = Singleton04.getInstance();
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
long endTime = System.currentTimeMillis();
System.out.println("懒汉式单例模式总消耗时间:" + (endTime - startTime) + "毫秒");
}
}
最后就很简单了,运行起来,可以看到各个不同的模式的效率:
由图上很简单可以看出,各自不同的特点,除了懒汉式,其它几种效率都不错,但是饿汉式因为不是延迟加载,所以某些场合下不适合,可能会造成开销增加,懒汉式支持延迟加载,但是因为线程安全问题,所以效率下降比较严重,考虑综合因素,结论是枚举类型是线程安全效率又高的,同时是非延迟加载的,内部类是支持延迟加载的,也是线程安全的,而且性能也不错。