单例模式


23种设计模式

1.单例模式

单例模式主要是保证只有一个实例对象。

2.单例模式实现方式

1.饿汉式–静态常量
2.饿汉式–静态代码块
3.懒汉式–常见
4.懒汉式–同步方法
5.懒汉式–同步代码块
6.双重检查
7.静态内部类
8.枚举

3.构思对比项目

3.1对比方式

使用多线程的方式,同步访问单例模式的实例对象

3.2单例基类设计

import java.util.ArrayList;
import java.util.List;

public abstract class Singleton {

private boolean isShow = false;

public abstract void showName();

private List<String> list = new ArrayList<String>();

protected void add(String string){
list.add(string);
}

protected void show(){

for(int i = 0;i < list.size();i++){
if(isShow)
System.out.println(list.get(i));
}
System.out.println("总计:\t"+list.size());
System.out.println();
Runtime rt = Runtime.getRuntime();
showName();
System.out.println("当前可用内存:\t"+rt.freeMemory());
System.out.println("结束:\t"+System.currentTimeMillis());
}
}

说明:采用模板方法的设计模式,由基类规定方法的调用,以及要求子类必须实现的方法。
其中:为单例类抽取属性:isShow=====是否显示输出list中的每一项
list是多线程操作的对象,每一个线程对单例类的操作是添加到list中一个字符串
showName()是一个抽象方法,是基类要求子类必须实现的方法,这个方法输出了正在运行的单例对象所属的实现方式。
show方法输出此时系统的一些状态属性。

3.3线程基类

public abstract class Test implements Runnable {

protected Integer index;

public Test(Integer integer) {
this.index = integer;
}

@Override
public abstract void run();

}

说明:线程基类使用的是实现Runnable接口实现多线程。

3.4测试类基类设计

/**
* 单例模式可以说是设计模式中最简单的一个设计模式 单例模式需要做的事情就是保证全局的实例对象是唯一的 因此,本次学习将尝试使用多线程并发来测试单例模式
*/
public abstract class Main {

protected Integer sum = 1000;

public void doTest(Class<?> test) {
setThread();
try {
Thread.sleep(500);
} catch (Exception e) {
e.getMessage();
}
output();
}

public abstract void setThread();

public abstract void output();

}

说明:测试基类有一个sum属性,这个属性控制对每一个单例实例对象进行访问的次数了,当sum=100表示将有100个线程对每一种实现的单例类的实例对象进行访问。
doTest()方法用来等待创建线程完成,或者定义如何创建线程和如何输出系统信息。
setThread方法表示测试子类必须实现对相应的线程进行自己的设置
output方法表示测试子类必须实现输出系统状态的方法。

4单例模式具体实现

4.1静态常量–饿汉式

/**
* 第一种:静态常量--饿汉式
* 分析:因为Singleton1的唯一实例在类被加载时就进行创建,
* 所以可以很好的解决线程安全的问题
* 缺点:有一定的可能性造成内存浪费,特别是如果单例对象中,
* 保存有较大数据或者对象,但是在整个生命周期都没有被使用,
* 那么会造成内存浪费。
*
*/
public class Singleton1 extends Singleton{

private final String NAME = "第一种:静态常量--饿汉式";

private final static Singleton1 INSTANCE = new Singleton1();

private Singleton1(){

}

public static Singleton1 getInstance(){
return INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}

}

4.2饿汉式,静态代码块

/**
* 2.饿汉式,静态代码块 与第一种完全相同,只是写法不同
*/

public class Singleton2 extends Singleton {

private final String NAME = "2.饿汉式,静态代码块";

private static Singleton2 INSTANCE;

static {
INSTANCE = new Singleton2();
}

private Singleton2() {

}

public static Singleton2 getInstance() {
return INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}


}

4.3懒汉式–常规

package cn.com.startimes.Singleton;
/**
* 3.懒汉式--常规
* 节省内存,懒创建,使用时创建
* 缺点:线程不安全,只能在单线程下使用。
*/

public class Singleton3 extends Singleton{

private final String NAME = "3.懒汉式--常规";

private static Singleton3 INSTANCE;

private Singleton3(){

}

public static Singleton3 getInstance(){

if(INSTANCE == null){
INSTANCE = new Singleton3();
}


return INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}

}

4.4懒汉式,同步方法

/**
*
* 4.懒汉式,同步方法
*
*/
public class Singleton4 extends Singleton {

private final String NAME = "4.懒汉式,同步方法";

private static Singleton4 INSTANCE;

private Singleton4() {

}

public static synchronized Singleton4 getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton4();
}
return INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}


}

4.5懒汉式–同步代码块

/**
* 5.懒汉式--同步代码块
*
*
*/
public class Singleton5 extends Singleton {

private final String NAME = "5.懒汉式--同步代码块";

private static Singleton5 INSTANCE;

private Singleton5() {

}

public static Singleton5 getInstance() {
if (INSTANCE == null) {
synchronized (Singleton5.class) {
INSTANCE = new Singleton5();
}
}
return INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}



}

4.6双重检查

/**
* 6.双重检查
*
*
*/
public class Singleton6 extends Singleton{

private final String NAME = "6.双重检查";

private static volatile Singleton6 INSTANCE;

private Singleton6(){

}

public static Singleton6 getInstance(){
if(INSTANCE == null){
synchronized(Singleton6.class){
if(INSTANCE == null){
INSTANCE = new Singleton6();
}
}
}
return INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}

}

4.7静态内部类

/**
* 7.静态内部类
*
*
*/
public class Singleton7 extends Singleton {

private final String NAME = "7.静态内部类";

private Singleton7() {

}

private static class Inner {
private static final Singleton7 INSTANCE = new Singleton7();
}

public static Singleton7 getInstance() {
return Inner.INSTANCE;
}

@Override
public void showName() {
System.out.println(NAME);
}

}

4.8枚举

package cn.com.startimes.Singleton;

import java.util.ArrayList;
import java.util.List;

/**
* 8.枚举
*
*
*/
public enum Singleton8{
INSTANCE;

private boolean isShow = false;

private final String NAME = "8.枚举";

public static Singleton8 getInstance(){
return INSTANCE;
}

private List<String> list = new ArrayList<String>();

public void add(String string){
list.add(string);
}

public void show(){
for(int i = 0;i < list.size();i++){
if(isShow)
System.out.println(list.get(i));
}
System.out.println("总计:\t"+list.size());
System.out.println();
Runtime rt = Runtime.getRuntime();
showName();
System.out.println("当前可用内存:\t"+rt.freeMemory());
System.out.println("结束:\t"+System.currentTimeMillis());
}

public void showName(){
System.out.println(NAME);
}

}

5.线程类具体实现

5.1—4.1

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test1 extends Test{

public Test1(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton1.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.2–4.2

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test2 extends Test{

public Test2(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton2.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.3-4.3

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test3 extends Test{

public Test3(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton3.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.4–4.4

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test4 extends Test{

public Test4(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton4.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.5–4.5

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test5 extends Test{

public Test5(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton5.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.6–4.6

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test6 extends Test{

public Test6(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton6.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.7–4.7

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test7 extends Test{

public Test7(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton7.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

5.8–4.8

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test8 extends Test{

public Test8(Integer integer) {
super(integer);
}

@Override
public void run() {
Singleton8.getInstance().add(
new SimpleDateFormat("HH:mm:ss,sss\t\t\t").format(new Date())
.toString() + super.index);
}

}

6测试类具体实现

6.1–4.1–5.1

public class Main1 extends Main {

public static void main(String[] args) {
Main1 obj = new Main1();
obj.doTest(Test1.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test1(i), i + "").start();
}
}

@Override
public void output() {
Singleton1.getInstance().show();
}

}

6.2–4.2–5.2

public class Main2 extends Main {

public static void main(String[] args) {
Main2 obj = new Main2();
obj.doTest(Test2.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test2(i), i + "").start();
}
}

@Override
public void output() {
Singleton2.getInstance().show();
}

}

6.3–4.3–5.3

/**
* 线程不安全,因为存在可能创建多个实例, 那么后面的实例会覆盖掉之前的实例,造成数据丢失
*
*/
public class Main3 extends Main {

public static void main(String[] args) {
Main3 obj = new Main3();
obj.doTest(Test3.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test3(i), i + "").start();
}
}

@Override
public void output() {
Singleton3.getInstance().show();
}

}

6.4–4.4–5.4

public class Main4 extends Main{

public static void main(String[] args) {
Main4 obj = new Main4();
obj.doTest(Test4.class);
}

@Override
public void setThread() {
for(int i = 0; i < sum;i++){
new Thread(new Test4(i),i+"").start();
}
}

@Override
public void output() {
Singleton4.getInstance().show();
}

}

6.5–4.5–5.5

public class Main5 extends Main {

public static void main(String[] args) {
Main5 obj = new Main5();
obj.doTest(Test5.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test5(i), i + "").start();
}
}

@Override
public void output() {
Singleton5.getInstance().show();
}

}

6.6–4.6–5.6

public class Main6 extends Main{

public static void main(String[] args) {
Main6 obj = new Main6();
obj.doTest(Test6.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test6(i), i + "").start();
}
}

@Override
public void output() {
Singleton6.getInstance().show();
}

}

6.7–4.7–5.7

public class Main7 extends Main {

public static void main(String[] args) {
Main7 obj = new Main7();
obj.doTest(Test7.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test7(i), i + "").start();
}
}

@Override
public void output() {
Singleton7.getInstance().show();
}

}

6.8–4.8–5.8

public class Main8 extends Main {

public static void main(String[] args) {
Main8 obj = new Main8();
obj.doTest(Test8.class);
}

@Override
public void setThread() {
for (int i = 0; i < sum; i++) {
new Thread(new Test8(i), i + "").start();
}
}

@Override
public void output() {
Singleton8.getInstance().show();
}

}

7项目主方法

public class RealMain {

public static void startTime(){
System.out.println("开始:\t"+System.currentTimeMillis());
}

public static void endTime(){
System.out.println("结束:\t"+System.currentTimeMillis());
}

public static void startMemory(){
Runtime rt = Runtime.getRuntime();
System.out.println("当前可用内存"+rt.freeMemory());
System.out.println("消耗的内存"+(rt.totalMemory() - rt.freeMemory()));
}


public static void sleep(Long time){
System.out.println("线程睡眠"+time+"毫秒");
try {
Thread.sleep(time);
} catch (Exception e) {
}
}

public static void main(String[] args) {

Runtime rt = Runtime.getRuntime();
System.out.println("初始总内存"+rt.totalMemory());
startMemory();
startTime();
Main1 main1 = new Main1();
main1.doTest(Test1.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main2 main2 = new Main2();
main2.doTest(Test2.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main3 main3 = new Main3();
main3.doTest(Test3.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main4 main4 = new Main4();
main4.doTest(Test4.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main5 main5 = new Main5();
main5.doTest(Test5.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main6 main6 = new Main6();
main6.doTest(Test6.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main7 main7 = new Main7();
main7.doTest(Test7.class);

sleep(1000L);
System.out.println();

startTime();
startMemory();
Main8 main8 = new Main8();
main8.doTest(Test8.class);

}

}

8.测试结果

8.1----sum=10

初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540293390768
总计: 8

第一种:静态常量--饿汉式
当前可用内存: 14969464
结束: 1540293391311
线程睡眠1000毫秒

开始: 1540293392311
当前可用内存14969464
消耗的内存1283464
总计: 8

2.饿汉式,静态代码块
当前可用内存: 14063888
结束: 1540293392917
线程睡眠1000毫秒

开始: 1540293393917
当前可用内存14063888
消耗的内存2189040
总计: 8

3.懒汉式--常规
当前可用内存: 13067696
结束: 1540293394420
线程睡眠1000毫秒

开始: 1540293395420
当前可用内存13067696
消耗的内存3185232
总计: 8

4.懒汉式,同步方法
当前可用内存: 12162232
结束: 1540293395943
线程睡眠1000毫秒

开始: 1540293396944
当前可用内存12162232
消耗的内存4090696
总计: 6

5.懒汉式--同步代码块
当前可用内存: 15195944
结束: 1540293397468
线程睡眠1000毫秒

开始: 1540293398468
当前可用内存15195944
消耗的内存1056984
总计: 8

6.双重检查
当前可用内存: 14968912
结束: 1540293398970
线程睡眠1000毫秒

开始: 1540293399970
当前可用内存14968912
消耗的内存1284016
总计: 8

7.静态内部类
当前可用内存: 14741768
结束: 1540293400481
线程睡眠1000毫秒

开始: 1540293401482
当前可用内存14741768
消耗的内存1511160
总计: 9

8.枚举
当前可用内存: 14465488
结束: 1540293402022

方式

静态常量

静态代码块

常见

同步方法

同步代码块

双重检查

静态内部类

枚举

开始

1540293390768

1540293392311

1540293393917

1540293395420

1540293396944

1540293398468

1540293399970

1540293401482

结束

1540293391311

1540293392917

1540293394420

1540293395943

1540293397468

1540293398970

1540293400481

1540293402022

剩余内存

14969464

14063888

13067696

12162232

15195944

14968912

14741768

14465488

消耗内存

287832

1283464

2189040

3185232

4090696

1056984

1284016

1511160

list.size

8

8

8

8

6

8

8

9

8.2----sum=100

初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540294269587
总计: 100

第一种:静态常量--饿汉式
当前可用内存: 12592952
结束: 1540294270144
线程睡眠1000毫秒

开始: 1540294271145
当前可用内存12592952
消耗的内存3659976
总计: 98

2.饿汉式,静态代码块
当前可用内存: 12370176
结束: 1540294271683
线程睡眠1000毫秒

开始: 1540294272683
当前可用内存12321224
消耗的内存3931704
总计: 95

3.懒汉式--常规
当前可用内存: 12098560
结束: 1540294273189
线程睡眠1000毫秒

开始: 1540294274189
当前可用内存12098560
消耗的内存4154368
总计: 97

4.懒汉式,同步方法
当前可用内存: 11826880
结束: 1540294274718
线程睡眠1000毫秒

开始: 1540294275719
当前可用内存11826880
消耗的内存4426048
总计: 91

5.懒汉式--同步代码块
当前可用内存: 11555296
结束: 1540294276232
线程睡眠1000毫秒

开始: 1540294277232
当前可用内存11555296
消耗的内存4697632
总计: 98

6.双重检查
当前可用内存: 15639728
结束: 1540294277767
线程睡眠1000毫秒

开始: 1540294278767
当前可用内存15639728
消耗的内存613200
总计: 97

7.静态内部类
当前可用内存: 15304528
结束: 1540294279273
线程睡眠1000毫秒

开始: 1540294280273
当前可用内存15304528
消耗的内存948400
Exception in thread "39" java.lang.ArrayIndexOutOfBoundsException: 58
at java.util.ArrayList.add(ArrayList.java:352)
at cn.com.startimes.Singleton.Singleton8.add(Singleton8.java:25)
at cn.com.startimes.Singleton.Test8.run(Test8.java:14)
at java.lang.Thread.run(Thread.java:662)
总计: 97

8.枚举
当前可用内存: 15000976
结束: 1540294280812

方式

静态常量

静态代码块

常见

同步方法

同步代码块

双重检查

静态内部类

枚举

开始

1540294269587

1540294271145

1540294272683

1540294274189

1540294275719

1540294277232

1540294278767

1540294280273

结束

1540294270144

1540294271683

1540294273189

1540294274718

1540294276232

1540294277767

1540294279273

1540294280812

剩余内存

12592952

12370176

12098560

11826880

11555296

15639728

15304528

15000976

消耗内存

287832

3659976

3931704

4154368

4426048

4697632

613200

948400

list.size

100

98

95

97

91

98

97

97

8.3----sum=1000

初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540294686378
总计: 1000

第一种:静态常量--饿汉式
当前可用内存: 14595808
结束: 1540294686966
线程睡眠1000毫秒

开始: 1540294687966
当前可用内存14595808
消耗的内存1657120
总计: 999

2.饿汉式,静态代码块
当前可用内存: 12025192
结束: 1540294688518
线程睡眠1000毫秒

开始: 1540294689518
当前可用内存12025192
消耗的内存4227736
总计: 999

3.懒汉式--常规
当前可用内存: 13581920
结束: 1540294690063
线程睡眠1000毫秒

开始: 1540294691063
当前可用内存13581920
消耗的内存2671008
总计: 1000

4.懒汉式,同步方法
当前可用内存: 14779736
结束: 1540294691606
线程睡眠1000毫秒

开始: 1540294692607
当前可用内存14779736
消耗的内存1473192
总计: 990

5.懒汉式--同步代码块
当前可用内存: 14833528
结束: 1540294693150
线程睡眠1000毫秒

开始: 1540294694150
当前可用内存14833528
消耗的内存1419400
总计: 1000

6.双重检查
当前可用内存: 12631504
结束: 1540294694696
线程睡眠1000毫秒

开始: 1540294695696
当前可用内存12631504
消耗的内存3621424
总计: 1000

7.静态内部类
当前可用内存: 11329760
结束: 1540294696242
线程睡眠1000毫秒

开始: 1540294697242
当前可用内存11329760
消耗的内存4923168
总计: 998

8.枚举
当前可用内存: 15323136
结束: 1540294697788

8.4----sum=10000

初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540294985030
总计: 10000

第一种:静态常量--饿汉式
当前可用内存: 14475208
结束: 1540294985997
线程睡眠1000毫秒

开始: 1540294986997
当前可用内存14475208
消耗的内存1777720
总计: 10000

2.饿汉式,静态代码块
当前可用内存: 10917576
结束: 1540294987916
线程睡眠1000毫秒

开始: 1540294988916
当前可用内存10917576
消耗的内存5335352
总计: 9998

3.懒汉式--常规
当前可用内存: 12036128
结束: 1540294989840
线程睡眠1000毫秒

开始: 1540294990840
当前可用内存12034080
消耗的内存4218848
总计: 10000

4.懒汉式,同步方法
当前可用内存: 9795360
结束: 1540294991761
线程睡眠1000毫秒

开始: 1540294992761
当前可用内存9793264
消耗的内存6459664
总计: 9986

5.懒汉式--同步代码块
当前可用内存: 9340936
结束: 1540294993679
线程睡眠1000毫秒

开始: 1540294994679
当前可用内存9338824
消耗的内存6914104
总计: 10000

6.双重检查
当前可用内存: 7792000
结束: 1540294995598
线程睡眠1000毫秒

开始: 1540294996598
当前可用内存7792000
消耗的内存8463024
总计: 9999

7.静态内部类
当前可用内存: 6106208
结束: 1540294997516
线程睡眠1000毫秒

开始: 1540294998516
当前可用内存6106208
消耗的内存10146720
总计: 9998

8.枚举
当前可用内存: 6363688
结束: 1540294999438

8.5----sum=10 0000

初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540295055474
总计: 99993

第一种:静态常量--饿汉式
当前可用内存: 6316656
结束: 1540295060124
线程睡眠1000毫秒

开始: 1540295061124
当前可用内存6316656
消耗的内存9936272
总计: 100000

2.饿汉式,静态代码块
当前可用内存: 13416304
结束: 1540295065718
线程睡眠1000毫秒

开始: 1540295066719
当前可用内存13414208
消耗的内存28725440
总计: 99995

3.懒汉式--常规
当前可用内存: 7869048
结束: 1540295071313
线程睡眠1000毫秒

开始: 1540295072313
当前可用内存7866920
消耗的内存34272728
总计: 99996

4.懒汉式,同步方法
当前可用内存: 14200352
结束: 1540295076930
线程睡眠1000毫秒

开始: 1540295077930
当前可用内存14200352
消耗的内存55263712
总计: 99980

5.懒汉式--同步代码块
当前可用内存: 10302304
结束: 1540295082537
线程睡眠1000毫秒

开始: 1540295083537
当前可用内存10302304
消耗的内存59161760
总计: 99993

6.双重检查
当前可用内存: 32648592
结束: 1540295088206
线程睡眠1000毫秒

开始: 1540295089206
当前可用内存32648592
消耗的内存75416176
总计: 99998

7.静态内部类
当前可用内存: 45894856
结束: 1540295093839
线程睡眠1000毫秒

开始: 1540295094839
当前可用内存45894856
消耗的内存62169912
总计: 99999

8.枚举
当前可用内存: 25585288
结束: 1540295099470

8.6----sum=100 0000


初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540295151282
总计: 999976

第一种:静态常量--饿汉式
当前可用内存: 59587368
结束: 1540295193482
线程睡眠1000毫秒

开始: 1540295194482
当前可用内存59585280
消耗的内存106188032
总计: 999815

2.饿汉式,静态代码块
当前可用内存: 18830360
结束: 1540295244347
线程睡眠1000毫秒

开始: 1540295245347
当前可用内存18828312
消耗的内存240694248
总计: 999937

3.懒汉式--常规
当前可用内存: 1967848
结束: 1540295318183
线程睡眠1000毫秒

开始: 1540295319184
当前可用内存1966792
消耗的内存257556000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at cn.com.startimes.Singleton.Main4.setThread(Main4.java:13)
at cn.com.startimes.Singleton.Main.doTest(Main.java:12)
at cn.com.startimes.Singleton.RealMain.main(RealMain.java:59)
Exception in thread "87082" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.<init>(HashMap.java:187)
at java.util.HashMap.<init>(HashMap.java:199)
at java.util.ListResourceBundle.loadLookup(ListResourceBundle.java:172)
at java.util.ListResourceBundle.handleGetObject(ListResourceBundle.java:106)
at java.util.ResourceBundle.getObject(ResourceBundle.java:368)
at java.util.ResourceBundle.getObject(ResourceBundle.java:371)
at java.util.ResourceBundle.getStringArray(ResourceBundle.java:351)
at java.text.DateFormatSymbols.initializeData(DateFormatSymbols.java:622)
at java.text.DateFormatSymbols.<init>(DateFormatSymbols.java:123)
at java.text.DateFormatSymbols.getCachedInstance(DateFormatSymbols.java:328)
at java.text.DateFormatSymbols.getInstanceRef(DateFormatSymbols.java:302)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:498)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:475)
at cn.com.startimes.Singleton.Test4.run(Test4.java:15)
at java.lang.Thread.run(Thread.java:662)
Exception in thread "87086" java.lang.OutOfMemoryError: Java heap space
at java.lang.Object.clone(Native Method)
at java.util.TimeZone.clone(TimeZone.java:696)
at sun.util.calendar.ZoneInfo.clone(ZoneInfo.java:689)
at java.util.TimeZone.getDefault(TimeZone.java:515)
at java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:598)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:496)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:475)
at cn.com.startimes.Singleton.Test4.run(Test4.java:15)
at java.lang.Thread.run(Thread.java:662)

一起执行发现内存不够,所以呢,一个一个的执行:

8.6.1

初始总内存16252928
当前可用内存15965096
消耗的内存287832
开始: 1540295518312
总计: 999968

第一种:静态常量--饿汉式
当前可用内存: 54538064
结束: 1540295560328
线程睡眠1000毫秒

8.6.2

初始总内存16252928
开始: 1540295611141
当前可用内存15965096
消耗的内存287832
总计: 999975

2.饿汉式,静态代码块
当前可用内存: 21531648
结束: 1540295653102
线程睡眠1000毫秒

8.6.3

初始总内存16252928
开始: 1540295686658
当前可用内存15965096
消耗的内存287832
总计: 999930

3.懒汉式--常规
当前可用内存: 56398800
结束: 1540295730306
线程睡眠1000毫秒

8.6.4

初始总内存16252928
开始: 1540295765798
当前可用内存15965096
消耗的内存287832
总计: 999981

4.懒汉式,同步方法
当前可用内存: 56129152
结束: 1540295808964
线程睡眠1000毫秒

8.6.5

初始总内存16252928
开始: 1540295886300
当前可用内存15965096
消耗的内存287832
总计: 999974

5.懒汉式--同步代码块
当前可用内存: 28563256
结束: 1540295927973
线程睡眠1000毫秒

8.6.6

初始总内存16252928
开始: 1540295968057
当前可用内存15965096
消耗的内存287832
总计: 999958

6.双重检查
当前可用内存: 32765968
结束: 1540296010265
线程睡眠1000毫秒

8.6.7

初始总内存16252928
开始: 1540296051198
当前可用内存15965096
消耗的内存287832
总计: 999969

7.静态内部类
当前可用内存: 56959392
结束: 1540296092718
线程睡眠1000毫秒

8.6.8

初始总内存16252928
开始: 1540296137102
当前可用内存15965096
消耗的内存287832
总计: 999962

8.枚举
当前可用内存: 67777208
结束: 1540296178511

9测试可靠性

说明:之前的测试中list.size因为子线程并没有全部结束,所以输出的结果与预期有差别,这是正常的。

记得修改sum

接下来是测试可靠性的过程与方法:

9.1方法

检测线程数目,当线程数目等于1时(只剩下主线程),输出系统状态(调用单例类的shwo方法)

9.2过程

新建一个带有静态主方法main方法的类:

/**
* 创建100个线程去访问单例对象的list
* 同时对list进行增加操作,最后输出list的内容
*
*
*/

public class OneMain {

public static void main(String[] args) {

Main1 main1 = new Main1();
main1.doTest(Test1.class);

Main2 main2 = new Main2();
main2.doTest(Test2.class);

Main3 main3 = new Main3();
main3.doTest(Test3.class);

Main4 main4 = new Main4();
main4.doTest(Test4.class);

Main5 main5 = new Main5();
main5.doTest(Test5.class);

Main6 main6 = new Main6();
main6.doTest(Test6.class);

Main7 main7 = new Main7();
main7.doTest(Test7.class);

Main8 main8 = new Main8();
main8.doTest(Test8.class);

try{
while(Thread.activeCount() != 1){
Thread.sleep(5000);
}
} catch(Exception e){
e.getMessage();
}

System.out.println();
System.out.println();
System.out.println();
System.out.println();


System.out.println(Thread.activeCount());
Singleton1.getInstance().show();
Singleton2.getInstance().show();
Singleton3.getInstance().show();
Singleton4.getInstance().show();
Singleton5.getInstance().show();
Singleton6.getInstance().show();
Singleton7.getInstance().show();
Singleton8.getInstance().show();
}

}

9.3结果

总计: 99

第一种:静态常量--饿汉式
当前可用内存: 13085400
结束: 1540296929928
总计: 99

2.饿汉式,静态代码块
当前可用内存: 12831184
结束: 1540296930434
总计: 99

3.懒汉式--常规
当前可用内存: 12576928
结束: 1540296930940
总计: 99

4.懒汉式,同步方法
当前可用内存: 12291264
结束: 1540296931448
总计: 96

5.懒汉式--同步代码块
当前可用内存: 12037016
结束: 1540296931954
总计: 99

6.双重检查
当前可用内存: 11751184
结束: 1540296932461
总计: 98

7.静态内部类
当前可用内存: 11491904
结束: 1540296932968
总计: 99

8.枚举
当前可用内存: 15660968
结束: 1540296933477




1
总计: 99

第一种:静态常量--饿汉式
当前可用内存: 15660968
结束: 1540296933477
总计: 99

2.饿汉式,静态代码块
当前可用内存: 15660968
结束: 1540296933477
总计: 99

3.懒汉式--常规
当前可用内存: 15660968
结束: 1540296933477
总计: 99

4.懒汉式,同步方法
当前可用内存: 15660968
结束: 1540296933477
总计: 96

5.懒汉式--同步代码块
当前可用内存: 15660968
结束: 1540296933477
总计: 99

6.双重检查
当前可用内存: 15660968
结束: 1540296933477
总计: 98

7.静态内部类
当前可用内存: 15660968
结束: 1540296933478
总计: 99

8.枚举
当前可用内存: 15660968
结束: 1540296933478

9.4另一种方式

9.4.1单例类基类增加方法

protected void getSize(){
System.out.println(list.size());
}

9.4.2测试主类

/**
* 创建100个线程去访问单例对象的list
* 同时对list进行增加操作,最后输出list的内容
*
*
*/

public class OneMain {

public static void main(String[] args) {

Main1 main1 = new Main1();
main1.doTest(Test1.class);

Main2 main2 = new Main2();
main2.doTest(Test2.class);

Main3 main3 = new Main3();
main3.doTest(Test3.class);

Main4 main4 = new Main4();
main4.doTest(Test4.class);

Main5 main5 = new Main5();
main5.doTest(Test5.class);

Main6 main6 = new Main6();
main6.doTest(Test6.class);

Main7 main7 = new Main7();
main7.doTest(Test7.class);

Main8 main8 = new Main8();
main8.doTest(Test8.class);

try{
while(Thread.activeCount() != 1){
Thread.sleep(5000);
}
} catch(Exception e){
e.getMessage();
}

System.out.println();
System.out.println();
System.out.println();
System.out.println();


System.out.println(Thread.activeCount());
Singleton1.getInstance().getSize();
Singleton2.getInstance().getSize();
Singleton3.getInstance().getSize();
Singleton4.getInstance().getSize();
Singleton5.getInstance().getSize();
Singleton6.getInstance().getSize();
Singleton7.getInstance().getSize();
Singleton8.getInstance().getSize();
}

}

9.4.3结果

总计: 100

第一种:静态常量--饿汉式
当前可用内存: 13026272
结束: 1540297109882
总计: 99

2.饿汉式,静态代码块
当前可用内存: 12772128
结束: 1540297110389
总计: 96

3.懒汉式--常规
当前可用内存: 12517888
结束: 1540297110894
总计: 99

4.懒汉式,同步方法
当前可用内存: 12232224
结束: 1540297111402
总计: 95

5.懒汉式--同步代码块
当前可用内存: 11978000
结束: 1540297111908
总计: 99

6.双重检查
当前可用内存: 11692288
结束: 1540297112416
总计: 100

7.静态内部类
当前可用内存: 15892832
结束: 1540297112924
总计: 100

8.枚举
当前可用内存: 15544072
结束: 1540297113431




1
100
99
96
99
95
99
100
100

10补充

发现试验结果与预期有一定的区别,所以,使用调试的方式查看具体的值:
首先在主程序:OneMain的主方法中,当线程为1后面的代码处设置断点
结果如下:

10.1第一次测试结果

23种设计模式----单例模式----创建型模式_创建型模式

23种设计模式----单例模式----创建型模式_8种实现_02

23种设计模式----单例模式----创建型模式_23种设计模式_03

23种设计模式----单例模式----创建型模式_单例模式_04

23种设计模式----单例模式----创建型模式_8种实现_05

23种设计模式----单例模式----创建型模式_23种设计模式_06

23种设计模式----单例模式----创建型模式_23种设计模式_07

23种设计模式----单例模式----创建型模式_创建型模式_08

10.2第二次测试

23种设计模式----单例模式----创建型模式_设计模式_09

23种设计模式----单例模式----创建型模式_单例模式_10

23种设计模式----单例模式----创建型模式_单例模式_11

23种设计模式----单例模式----创建型模式_创建型模式_12

23种设计模式----单例模式----创建型模式_23种设计模式_13

23种设计模式----单例模式----创建型模式_8种实现_14

23种设计模式----单例模式----创建型模式_单例模式_15

23种设计模式----单例模式----创建型模式_单例模式_16