1.饿汉式单例
示例:
/**
* 单例模式1:饿汉式
* @author bruceliu
* @create 2019-02-28 11:27
*/
public class MySingeleton {
private static MySingeleton instance=new MySingeleton();
public MySingeleton(){
}
public static MySingeleton getInstance(){
return instance;
}
}
测试代码:
/**
* 测试饿汉式
*
* @author bruceliu
* @create 2019-02-28 11:32
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingeleton.getInstance() + "---->hashcode:" + MySingeleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads = new TestMySingeleton[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new TestMySingeleton();
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
对象地址:com.bruceliu.demo3.MySingeleton@60c8c409---->hashcode:1623770121
从运行结果可以看出实例变量额hashCode值一致,这说明对象是同一个。
2.懒汉式单例
示例:
/**
* 单例设计模式:懒汉式
* @author bruceliu
* @create 2019-02-28 11:38
*/
public class MySingleton {
private static MySingeleton instace=null;
private MySingleton(){
}
public static MySingeleton getInstace(){
if(instace==null){
try {
//创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(3000);
instace=new MySingeleton();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return instace;
}
}
测试代码:
/**
* 测试懒汉式单例设计模式
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstace() + "---->hashcode:" + MySingleton.getInstace().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo3.MySingeleton@1fee0706---->hashcode:1905381423
对象地址:com.bruceliu.demo3.MySingeleton@5f73095---->hashcode:100085909
对象地址:com.bruceliu.demo3.MySingeleton@43008f8f---->hashcode:1905381423
对象地址:com.bruceliu.demo3.MySingeleton@692db0ef---->hashcode:100085909
对象地址:com.bruceliu.demo3.MySingeleton@7e92ee0---->hashcode:1905381423
对象地址:com.bruceliu.demo3.MySingeleton@48e0ce1c---->hashcode:1176975728
对象地址:com.bruceliu.demo3.MySingeleton@46273970---->hashcode:1764602095
对象地址:com.bruceliu.demo3.MySingeleton@7397005b---->hashcode:1764602095
对象地址:com.bruceliu.demo3.MySingeleton@4e704f06---->hashcode:1315983110
对象地址:com.bruceliu.demo3.MySingeleton@7191d02f---->hashcode:1905381423
从这里执行结果可以看出,单例的线程安全性并没有得到保证.
3.懒汉式单例(线程安全-同步方法)
示例:
/**
* 线程安全的懒汉式单例-方法中声明synchronized关键字
*
* @author bruceliu
* @create 2019-02-28 21:03
*/
public class MySingleton {
private static MySingleton instance = null;
private MySingleton() {
}
public synchronized static MySingleton getInstance(){
try {
if(instance!=null){
}else{
//创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(3000);
instance=new MySingleton();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
测试代码:
/**
* 测试懒汉式单例设计模式-方法中声明synchronized关键字
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstance() + "---->hashcode:" + MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
对象地址:com.bruceliu.demo5.MySingleton@524a6f4d---->hashcode:1380609869
从执行结果上来看,问题已经解决了,但是这种实现方式的运行效率会很低。同步方法效率低,那我们考虑使用同步代码块来实现.
6.懒汉式单例(线程安全-同步代码块)
示例:
/**
* 线程安全的懒汉式单例-同步代码块实现
*
* @author bruceliu
* @create 2019-02-28 21:03
*/
public class MySingleton {
private static MySingleton instance = null;
private MySingleton() {
}
public static MySingleton getInstance() {
try {
synchronized (MySingleton.class) {
if (instance != null) {
} else {
//创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(3000);
instance = new MySingleton();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
测试代码:
/**
* 测试懒汉式单例设计模式-同步代码块实现
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstance() + "---->hashcode:" + MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
对象地址:com.bruceliu.demo6.MySingleton@338637c5---->hashcode:864434117
这里的实现能够保证多线程并发下的线程安全性,但是这样的实现将全部的代码都被锁上了,同样的效率很低下。
7.懒汉式单例(线程安全-同步代码块-针对重要的代码进行同步)
示例:
/**
* 线程安全的懒汉式单例-同步代码块实现(缩小的同步代码块的粒度,但是这样还是可能存在线程不安全性)
*
* @author bruceliu
* @create 2019-02-28 21:12
*/
public class MySingleton {
private static MySingleton instance = null;
private MySingleton() {
}
public static MySingleton getInstance() {
try {
if (instance != null) {//懒汉式
} else {
//创建实例之前可能会有一些准备性的耗时工作
Thread.sleep(300);
synchronized (MySingleton.class) {
instance = new MySingleton();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
测试:
/**
* 测试懒汉式单例设计模式-同步代码块实现
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstance() + "---->hashcode:" + MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo7.MySingleton@14c448fe---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@1b094e2b---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@2a0170e1---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@79af4c1c---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@35655ed5---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@37e684d---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@505e1f21---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@2a75ae17---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@51d1628b---->hashcode:1348345633
对象地址:com.bruceliu.demo7.MySingleton@543fe730---->hashcode:1348345633
从运行结果来看,这样的方法进行代码块同步,代码的运行效率是能够得到提升,但是却没能保住线程的安全性。看来还得进一步考虑如何解决此问题。
8.双检查锁机制
示例:
/**
* Double Check Locking 双检查锁机制
* @author bruceliu
* @create 2019-02-28 21:14
*/
public class MySingleton {
//使用volatile关键字保其可见性
volatile private static MySingleton instance= null;
private MySingleton(){
}
public static MySingleton getInstance(){
try {
if(instance!=null){
}else{
//耗时操作
Thread.sleep(3000);
synchronized (MySingleton.class){
if(instance==null){
//二次检查
instance=new MySingleton();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
测试代码:
/**
* 测试懒汉式单例设计模式-Double Check Locking 双检查锁机制
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstance() + "---->hashcode:" + MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
从运行结果来看,该中方法保证了多线程并发下的线程安全性。
这里在声明变量时使用了volatile关键字来保证其线程间的可见性;在同步代码块中使用二次检查,以保证其不被重复实例化。集合其二者,这种实现方式既保证了其高效性,也保证了其线程安全性。
9.单例模式(静态内部类)
示例:
/**
* 使用静态内置类实现单例模式
* @author bruceliu
* @create 2019-02-28 21:20
*/
public class MySingleton {
//内部类
public static class MySingletonHandler {
private static MySingleton instance = new MySingleton();
}
private MySingleton() {
}
public static MySingleton getInstance() {
return MySingletonHandler.instance;
}
}
测试代码:
/**
* 使用静态内置类实现单例模式 测试
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstance() + "---->hashcode:" + MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
对象地址:com.bruceliu.demo9.MySingleton@49fb8056---->hashcode:1241219158
静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的
示例:
/**
* 静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的
* @author bruceliu
* @create 2019-02-28 21:25
*/
public class MySingleton implements Serializable {
private static final long serialVersionUID = 1L;
private static class MySingletonHandler {
private static MySingleton instance = new MySingleton();
}
private MySingleton(){}
public static MySingleton getInstance(){
return MySingletonHandler.instance;
}
}
测试代码:
/**
* 测试序列化与反序列化的单例模式实现
* @author bruceliu
* @create 2019-02-28 21:29
*/
public class SaveAndReadForSingleton {
public static void main(String[] args) {
MySingleton singleton = MySingleton.getInstance();
File file = new File("MySingleton.txt");
try {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(singleton);
fos.close();
oos.close();
System.out.println("--------->"+singleton.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
MySingleton rSingleton = (MySingleton) ois.readObject();
fis.close();
ois.close();
System.out.println("--------->"+rSingleton.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果:
--------->2133927002
--------->1836019240
解决办法就是在反序列化的过程中使用readResolve()方法,单例实现的代码如下:
/**
* 静态内部类虽然保证了单例在多线程并发下的线程安全性,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的
* @author bruceliu
* @create 2019-02-28 21:25
*/
public class MySingleton implements Serializable {
private static final long serialVersionUID = 1L;
private static class MySingletonHandler {
private static MySingleton instance = new MySingleton();
}
private MySingleton(){}
public static MySingleton getInstance(){
return MySingletonHandler.instance;
}
//该方法在反序列化时会被调用,该方法不是接口定义的方法
protected Object readResolve() throws ObjectStreamException {
System.out.println("调用了readResolve方法!");
return MySingletonHandler.instance;
}
}
运行结果:
--------->2133927002
调用了readResolve方法!
--------->2133927002
10.单例模式(静态代码块)
示例:
/**
* 使用static代码块实现单例
* @author bruceliu
* @create 2019-02-28 21:31
*/
public class MySingleton {
private static MySingleton instance=null;
private MySingleton(){
}
static {
instance=new MySingleton();
}
public static MySingleton getInstance(){
return instance;
}
}
测试代码:
/**
* 使用静态内置类实现单例模式 测试
* @author bruceliu
* @create 2019-02-28 11:43
*/
public class TestMySingeleton extends Thread {
@Override
public void run() {
System.out.println("对象地址:" + MySingleton.getInstance() + "---->hashcode:" + MySingleton.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingeleton[] threads=new TestMySingeleton[10];
for (int i = 0; i <threads.length ; i++) {
threads[i]=new TestMySingeleton();
}
for (int i = 0; i <threads.length ; i++) {
threads[i].start();
}
}
}
运行结果:
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
对象地址:com.bruceliu.demo11.MySingleton@586071af---->hashcode:1482715567
11.单例模式(枚举)
枚举enum和静态代码块的特性相似,在使用枚举时,构造方法会被自动调用,利用这一特性也可以实现单例
示例:
/**
* 使用枚举数据类型实现单例模式
*
* @author bruceliu
* @create 2019-02-28 21:36
*/
public enum EnumFactory {
singletonFactory;
private MySingleton instance;
private EnumFactory() {
//枚举类的构造方法在类加载是被实例化
instance = new MySingleton();
}
public MySingleton getInstance() {
return instance;
}
}
class MySingleton {
public MySingleton() {
}
}
测试代码:
/**
* 测试使用枚举数据类型实现单例模式
* @author bruceliu
* @create 2019-02-28 21:41
*/
public class TestMySingleton extends Thread {
@Override
public void run() {
System.out.println(EnumFactory.singletonFactory.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingleton[] mts = new TestMySingleton[10];
for (int i = 0; i < mts.length; i++) {
mts[i] = new TestMySingleton();
}
for (int j = 0; j < mts.length; j++) {
mts[j].start();
}
}
}
运行结果:
1416179411
1416179411
1416179411
1416179411
1416179411
1416179411
1416179411
1416179411
1416179411
1416179411
12.单例模式(枚举完善)
完善使用enum枚举实现单例模式,不暴露枚举类实现细节的封装代码
示例:
/**
* 完善使用enum枚举实现单例模式,不暴露枚举类实现细节的封装代码
* @author bruceliu
* @create 2019-02-28 21:44
*/
public class ClassFactory {
private enum MyEnumSingleton {
singletonFactory;
private MySingleton instance;
private MyEnumSingleton() {//枚举类的构造方法在类加载是被实例化
instance = new MySingleton();
}
public MySingleton getInstance() {
return instance;
}
}
public static MySingleton getInstance() {
return MyEnumSingleton.singletonFactory.getInstance();
}
}
class MySingleton {
public MySingleton() {
}
}
测试代码:
/**
* 完善使用enum枚举实现单例模式,不暴露枚举类实现细节的封装代码
* @author bruceliu
* @create 2019-02-28 21:41
*/
public class TestMySingleton extends Thread {
@Override
public void run() {
System.out.println(ClassFactory.getInstance().hashCode());
}
public static void main(String[] args) {
TestMySingleton[] mts = new TestMySingleton[10];
for (int i = 0; i < mts.length; i++) {
mts[i] = new TestMySingleton();
}
for (int j = 0; j < mts.length; j++) {
mts[j].start();
}
}
}
运行结果:
712355351
712355351
712355351
712355351
712355351
712355351
712355351
712355351
712355351
712355351