Java实现单例模式的两种方式
单例模式在实际开发中有很多的用途,比如我们在项目中常用的工具类,数据库等资源的连接类。这样做的好处是避免创建多个对象,占用内存资源,自始自终在内存中只有一个对象为我们服务。
单例对象一般有两种实现方式。懒汉式和饿汉式。
饿汉式实现如下:
package com.day05; /**
* 饿汉式
*
* @author Administrator
*
*/
public class Single {
// 定义一个个私有静态本类对象变量,饿汉式是一上来就给该变量进行初始化,加上final是让s这个对象引用始终保持不变,更为严谨
private static final Single s = new Single(); // 构造方法私有化,让外部无法通过new 关键字来进行创建对象
private Single() {
} // 暴露出一个外界可以获取该类对象的公共静态方法
public static Single getInstance() {
return s;
} }
测试类:
package com.day05;
public class SingleDemo {
public static void main(String[] args) {
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
System.out.println(s1==s2);
}
}
运行结果:
true
即s1==s2说明了,s1和s2在内存中地址都相等,即s1、和s2是同一个对象。
懒汉式实现如下:
package com.day05; /**
* 懒汉式
*
* @author Administrator
*
*/
public class Single {
// 定义一个个私有静态本类对象变量,懒汉式是先赋值为null,当需要的时候在初始化
private static Single s = null; // 构造方法私有化,让外部无法通过new 关键字来进行创建对象
private Single() {
} // 暴露出一个外界可以获取该类对象的公共静态方法
public static Single getInstance() {
if (s == null)
s = new Single();
return s;
} }
以上的代码如果是单线程的话就不会存在问题,但是当有多线程操作的时候,就会存在线程安全问题,演示代码如下:
package com.day05; /**
* 懒汉式
*
* @author Administrator
*
*/
public class Single {
// 定义一个个私有静态本类对象变量,懒汉式是先赋值为null,当需要的时候在初始化
private static Single s = null; // 构造方法私有化,让外部无法通过new 关键字来进行创建对象
private Single() {
} // 暴露出一个外界可以获取该类对象的公共静态方法
public static Single getInstance() {
if (s == null) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
s = new Single();
}
return s;
} }
测试类如下:
package com.day05;
public class SingleDemo implements Runnable {
public static void main(String[] args) {
SingleDemo sd = new SingleDemo();
new Thread(sd).start();
new Thread(sd).start();
}
@Override
public void run() {
Single s = Single.getInstance();
System.out.println(s);
}
}
运行结果如下:
com.day05.Single@4081b5a4
com.day05.Single@64dcdaac
可以发现每次运行结果打印出获取对象不是同一个,即存在线程安全问题。
问题分析:

由此我们可以采用Java给我们提供的同步锁来解决以上的问题,修改代码如下:
package com.day05; /**
* 懒汉式
*
* @author Administrator
*
*/
public class Single {
// 定义一个个私有静态本类对象变量,懒汉式是先赋值为null,当需要的时候在初始化
private static Single s = null; // 构造方法私有化,让外部无法通过new 关键字来进行创建对象
private Single() {
} // 暴露出一个外界可以获取该类对象的公共静态方法
public static synchronized Single getInstance() {
if (s == null) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
s = new Single();
}
return s;
} }
这样就解决了上面的代码存在的线程安全问题,但是同步锁虽然可以解决了线程安全问题,但是却会存在效率问题,所以我们可以采用双重判断的方法来优化一下改代码如下所示:
package com.day05; /**
* 懒汉式
*
* @author Administrator
*
*/
public class Single {
// 定义一个个私有静态本类对象变量,懒汉式是先赋值为null,当需要的时候在初始化
private static Single s = null; // 构造方法私有化,让外部无法通过new 关键字来进行创建对象
private Single() {
} // 暴露出一个外界可以获取该类对象的公共静态方法
// 这里需要注意的使静态共享数据使用的使该类的字节码对象即Single.class
public static Single getInstance() {
// 这里增加了一次判断,可以少一次进行锁的处理
if (s == null) {
synchronized (Single.class) {
if (s == null) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
s = new Single();
}
}
} return s;
} }
总结:还是比较推荐使用饿汉式,因为写法简单,不存在线程安全问题。
Java实现单例模式的两种方式的更多相关文章
- 对Java代码加密的两种方式,防止反编译
使用Virbox Protector对Java项目加密有两种方式,一种是对War包加密,一种是对Jar包加密.Virbox Protector支持这两种文件格式加密,可以加密用于解析class文件的j ...
- Java新建线程的两种方式
Java新建线程有两种方式,一种是通过继承Thread类,一种是实现Runnable接口,下面是新建线程的两种方式. 我们假设有个竞赛,有一个选手A做俯卧撑,一个选手B做仰卧起坐.分别为两个线程: p ...
- Java实现多线程的两种方式
实现多线程的两种方式: 方式1: 继承Thread类 A: 自定义MyThread类继承Thread类 B: 在MyThread类中重写run() C: 创建MyThread类的对象 D: 启动线程对 ...
- [Java] HashMap遍历的两种方式
Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml第一种: Map map = new HashMap( ...
- Java实现深克隆的两种方式
序列化和依次克隆各个可变的引用类型都可以实现深克隆,但是序列化的效率并不理想 下面是两种实现深克隆的实例,并且测试类对两种方法进行了对比: 1.重写clone方法使用父类中的clone()方法实现深克 ...
- java文件读写的两种方式
今天搞了下java文件的读写,自己也总结了一下,但是不全,只有两种方式,先直接看代码: public static void main(String[] args) throws IOExceptio ...
- K:java中序列化的两种方式—Serializable或Externalizable
在java中,对一个对象进行序列化操作,其有如下两种方式: 第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializ ...
- java 实现websocket的两种方式
简单说明 1.两种方式,一种使用tomcat的websocket实现,一种使用spring的websocket 2.tomcat的方式需要tomcat 7.x,JEE7的支持. 3.spring与we ...
- java实现同步的两种方式
同步是多线程中的重要概念.同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果.同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字. 给一个方法 ...
随机推荐
- 《暗黑世界V1.6》服务器代码执行图
<暗黑世界V1.6>服务器代码执行图 (原文地址:http://www.9miao.com/forum.php?mod=viewthread&tid=44016&highl ...
- linux/unix核心设计思想
1) 程序应该小而专一,程序应该尽量的小,且仅仅专注于一件事上.不要开发那些看起来实用可是90%的情况都用不到的特性: 2) 程序不仅仅要考虑性能, 程序的可移植性更重要,shell和perl.pyt ...
- GDB基本命令(整合)(转)
directory:添加源文件目录 l src.cpp:line_num可进入文件 如:l src.cpp:10 回车自动重复上一命令 一.gdb调试基本知识a.调试器指示的是将要执行的代码行b.只有 ...
- 设计模式之简单工厂模式(C#语言描述)
严格意义上来说,简单工厂模式并不属于GoF的23种设计模式,但是它是学习其他工厂模式的基础和前提条件.理解了简单工厂模式,学习工厂方法模式和抽象工厂模式会比较容易一些. 简单工厂模式的定义 定义一个工 ...
- tcp/ip ---数据链路层
- CentOS6.5配置PHP CI程序
步骤: 1.安装CentOS6.5系统: 1.选择PHP+Mysql环境 2.关闭防火墙和SeLinux 1.chkconfig --level 35 iptables off ...
- 167. Two Sum II - Input array is sorted【easy】
167. Two Sum II - Input array is sorted[easy] Given an array of integers that is already sorted in a ...
- 内核并发管理---spin lock
自旋锁最初是为了在smp系统上使用而设计. 1.在单处理器非抢占模式下,自旋锁不做任何事情. #ifdef CONFIG_PREEMPT_COUNT //支持抢占模式 #define pree ...
- NYOJ 诡异的电梯 && nyoj 1204 魔法少女
诡异的电梯[Ⅰ] 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 新的宿舍楼有 N(1≤N≤100000) 层 and M(1≤M≤100000)个学生. 在新的宿舍楼里 ...
- 谁说selenium打开firefox不用驱动的???!!!!
selenium3下写自动化脚本,使用firefox(48) 要下载驱动了 geckodriver 就是这个,和其他驱动放一个地方~~~