java设计模式 单例模式_java设计模式之--单例模式

前言:最近看完《java多线程编程核心技术》一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持。

单例模式,也就是一个类只有一个实例,任何对象要访问这个类只能通过这个实例对象来访问,我们把房子比喻一个java类,每个房子只有一把钥匙(好比每个类只有一个实例),这样唯有房子的主人才有这个钥匙才能访问房子,其他人访问不了。

我们来看一下怎么写一个单例模式的java代码,方法有很多种:

1.立即加载(也叫饿汉模式)

我们来看下具体的代码

packagesingleton;public classMyclass {//类加载初始化的时候就会生成一个实例

private static Myclass myclass=newMyclass();//把构造函数使用private修饰符修饰

privateMyclass() {

}public staticMyclass getInstance() {returnmyclass;

}

}

既然构造函数是私有的,那我们怎么调用这个类的对象呢?我们可以通过类名+方法的方式来获取这个对象,代码如下:

packagesingleton;public classTest1 {public static voidmain(String[] args) {//不能通过new来生成一个Myclass对象,编译报错//Myclass myclass=new Mycalss();

Myclass myclass1=Myclass.getInstance();

Myclass myclass2=Myclass.getInstance();//我们来打印一下上面两个对象的hashcode

System.out.println(myclass1.hashCode());

System.out.println(myclass2.hashCode());

}

}

b2b6bc3533701b009adec0e7c695811e.png

2.延迟加载(也叫懒汉模式)

下面我们来看看懒汉模式,也就是调用get方法的时候才实例化一个对象出来

packagesingleton;public classMyclass_1 {private staticMyclass_1 myclass_1;privateMyclass_1() {

}public staticMyclass_1 getInstance() {if (myclass_1!=null) {

}else{

myclass_1=newMyclass_1();

}returnmyclass_1;

}

}

测试代码

packagesingleton;public classTest1 {public static voidmain(String[] args) {//不能通过new来生成一个Myclass对象,编译报错//Myclass myclass=new Mycalss();

/*Myclass myclass1=Myclass.getInstance();

Myclass myclass2=Myclass.getInstance();*/Myclass_1 myclass1=Myclass_1.getInstance();

Myclass_1 myclass2=Myclass_1.getInstance();//我们来打印一下上面两个对象的hashcode

System.out.println(myclass1.hashCode());

System.out.println(myclass2.hashCode());

}

}

运行结果和上面的图是一样的

其实这里有一个很大的问题。那就是懒汉模式在多线程模式下是完全错误的

我们来看看在多线程下是什么样子的

线程类代码如下:

packagesingleton;public class Mythread extendsThread{public voidrun() {

System.out.println(Myclass_1.getInstance().hashCode());

}

}

测试代码:

packagesingleton;public classRunTest {public static voidmain(String[] args) {for (int i = 0; i < 3; i++) {newMythread().start();

}

}

}

运行结果

d16f264690415517d52cf8579fb22065.png

可以看出在多线程下生成了两个不同的实例对象。而我们想要的是单例啊

下面的做法是直接在用synchronized关键字修饰getInstance,但是这个这样会锁住整个方法,效率低下

packagesingleton;public classMyclass_1 {private staticMyclass_1 myclass_1;privateMyclass_1() {

}public static synchronizedMyclass_1 getInstance() {if (myclass_1!=null) {

}else{

myclass_1=newMyclass_1();

}returnmyclass_1;

}

}

下面的方法是使用同步语句块来做,效率也同样低下,和上面的做法半斤八两

packagesingleton;public classMyclass_1 {private staticMyclass_1 myclass_1;privateMyclass_1() {

}public staticMyclass_1 getInstance() {synchronized (Myclass_1.class) {if (myclass_1!=null) {

}else{

myclass_1=newMyclass_1();

}

}returnmyclass_1;

}

}

我们来看看最高效的方法吧(何为高效?就是尽量把锁住的代码块缩小范围而又不发生错误),使用DCK双检查锁机制来解决

代码如下:

packagesingleton;public classMyclass_1 {private staticMyclass_1 myclass_1;privateMyclass_1() {

}public staticMyclass_1 getInstance() {if (myclass_1!=null) {

}else{synchronized (Myclass_1.class) {

//再次判断if (myclass_1==null) {

myclass_1=newMyclass_1();

}

}

}returnmyclass_1;

}

}

欢迎访问我的个人网站

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值