该分类下的文章均为笔者阅读《Java程序性能优化》(葛一鸣)一书之所理解。如有欠缺,还请大佬们指点。
单例模式
单例模式用来创建的对象可以确保系统中只产生一个示例。主要有以下两种好处:
1.对于频繁使用的对象可以省略创建对象所花费的时间
2.由于new操作的次数减少,对系统内存的使用频率也会降低。将减轻GC压力。缩短GC停顿时间。
创建单例模式
public class SingleClassDemo {
//第一种方式 直接创建对象 需要时直接返回
public static SingleClassDemo sSingleClassDemo = new SingleClassDemo();
private SingleClassDemo() {
System.out.println("创建单例对象");
}
public static SingleClassDemo getInstance() {
return sSingleClassDemo;
}
// 该类中的其他静态方法
//public static String otherMethod() {
// return "otherMethod otherMethod!";
//}
}
/**
* 测试类
*/
public class TestSingleClassDemo {
@Test
public void testInstance() {
SingleClassDemo instance = SingleClassDemo.getInstance();
System.out.println(instance);
//打印结果:创建单例对象 top.wintp.demo.SingleClassDemo@50486d1d
}
}
如上述代码就是单例模式的一种简单的实现方式。试想我们这种实现方式会有什么问题呢?
当该类中存在其他的静态方法的时候,我们直接调用该类的其他静态方法,也会创建该类的对象,这是我们不想得到的结果
调用示例:
public class TestSingleClassDemo {
@Test
public void testInstance() {
//当调用该类的其他方法的时候,会初始化该类该类的静态变量 创建对象
String string = SingleClassDemo.otherMethod();
System.out.println(string);
//打印结果:创建单例对象 cotherMethod otherMethod!
}
}
单例模式优化一(懒加载模式)
修改创建单例对象的时机,当有需要的时候再去创建对象。
public class LazSingleClassDemo {
private static LazSingleClassDemo mLazSingleClassDemo = null;
private LazSingleClassDemo() {
System.out.println("创建懒加载模式的对象");
}
public static LazSingleClassDemo getmLazSingleClassDemo() {
if (mLazSingleClassDemo == null) {
mLazSingleClassDemo = new LazSingleClassDemo();
}
return mLazSingleClassDemo;
}
public static String otherMehod() {
return "otherMehod otherMehod";
}
}
public class TestSingleClassDemo {
@Test
public void testInstance() {
// 懒加载模式
//在懒加载模式中 调用该类的其他方法并不会创建该类的对象
String string = LazSingleClassDemo.otherMehod();
System.out.println(string);
//打印结果:otherMehod otherMehod
}
}
当多线程并发时,懒加载模式就可能会出现,当前线程检测为null,第二个线程检测为null,同时创建两个对象的情况。那就违背了单例的原则。
调用示例:
public class TestSingleClassDemo {
@Test
public void testInstance() {
// 懒加载模式的线程并发问题
new Thread("t1") {
public void run() {
LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(lazSingleClassDemo);
}
}.start();
new Thread("t2") {
public void run() {
LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(lazSingleClassDemo);
}
}.start();
new Thread("t3") {
public void run() {
LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(lazSingleClassDemo);
}
}.start();
new Thread("t4") {
public void run() {
LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(lazSingleClassDemo);
}
}.start();
new Thread("t5") {
public void run() {
LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(lazSingleClassDemo);
}
}.start();
/*
打印结果如下:
创建懒加载模式的对象
创建懒加载模式的对象
t2
top.wintp.demo.LazSingleClassDemo@475f260c
t1
top.wintp.demo.LazSingleClassDemo@55b9171e
t3
top.wintp.demo.LazSingleClassDemo@475f260c
t4
top.wintp.demo.LazSingleClassDemo@475f260c
t5
top.wintp.demo.LazSingleClassDemo@475f260c
*/
}
}
单例模式优化二(懒加载模式线程并发问题)
使用同步方法避免多线程并发。
public class LazSingleSyncClassDemo {
private static LazSingleSyncClassDemo mLazSingleClassDemo = null;
private LazSingleSyncClassDemo() {
System.out.println("创建懒加载模式同步方法的对象");
}
//使用synchronized 关键字
public static synchronized LazSingleSyncClassDemo getmLazSingleClassDemo() {
if (mLazSingleClassDemo == null) {
mLazSingleClassDemo = new LazSingleSyncClassDemo();
}
return mLazSingleClassDemo;
}
public static String otherMethod() {
return "otherMethod otherMethod";
}
}
如上代码,再次进行多线程进行调用就不会出现创建多个对象的结果
线程安全避免不了的就是性能会降低。下面就是线程同步与线程不同的测试程序执行时长
public class TestSingleClassDemo {
@Test
public void testInstance() {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
//懒加载模式 不同步方法 用时间: 2
beginTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
LazSingleSyncClassDemo lazSingleClassDemo = LazSingleSyncClassDemo.getmLazSingleClassDemo();
}
endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
//懒加载模式 同步方法 用时间: 5
}
}
单例模式优化三(使用静态内部类进行优化)
public class EndSingleClassDemo {
private static EndSingleClassDemo mLazSingleClassDemo = null;
private EndSingleClassDemo() {
System.out.println("创建懒加载模式的对象");
}
/**
* 静态内部类
*/
private static class EndSingleClassDemoHolder {
private static EndSingleClassDemo mLazSingleClassDemo = new EndSingleClassDemo();
}
public static EndSingleClassDemo getmLazSingleClassDemo() {
return EndSingleClassDemoHolder.mLazSingleClassDemo;
}
public static String otherMehod() {
return "otherMehod otherMehod";
}
}
public class TestSingleClassDemo {
@Test
public void testInstance() {
new Thread("t1") {
public void run() {
EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(endSingleClassDemo);
}
}.start();
new Thread("t2") {
public void run() {
EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(endSingleClassDemo);
}
}.start();
new Thread("t3") {
public void run() {
EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(endSingleClassDemo);
}
}.start();
new Thread("t4") {
public void run() {
EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(endSingleClassDemo);
}
}.start();
new Thread("t5") {
public void run() {
EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
System.out.println(this.getName());
System.out.println(endSingleClassDemo);
}
}.start();
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
}
long endTime = System.currentTimeMillis();
System.out.println("用时间:" + (endTime - beginTime));
/*
打印结果如下:
创建懒加载模式的对象
t1
t2
t3
top.wintp.demo.EndSingleClassDemo@4dbb3e34
top.wintp.demo.EndSingleClassDemo@4dbb3e34
top.wintp.demo.EndSingleClassDemo@4dbb3e34
t4
top.wintp.demo.EndSingleClassDemo@4dbb3e34
t5
top.wintp.demo.EndSingleClassDemo@4dbb3e34
用时间:1
*/
}
}
一个优秀的程序员,不仅要会编写程序,更要学会编写高质量的程序。
事虽难,做则成;路虽远,行则至。