单例模式的实现⽅式及如何有效防⽌防⽌反射和反序列化⽅式⼀:饿汉式(静态常量)
public class Singleton {
private final static Singleton SINGLETON = new Singleton();
private Singleton(){
}
public void doAction(){
//TODO 实现你需要做的事
}
public static Singleton getInstance(){
return SINGLETON;
}
}
测试⽤例:
public class Test {
public static void main(String[] args) {
Signleton singleton1 = Instance();
Signleton singleton2 = Instance();
System.out.println("两个singleton对象是否是同⼀个对象:"+ (singleton1 == singleton2) );
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
}
运⾏结果:
两个singleton对象是否是同⼀个对象:true
singleton1的hashCode:366712642
singleton2的hashCode:366712642
优点:
1. 代码实现简单
2. 利⽤类加载机制避免了多线程同步问题
缺点:
1. 在类加载时就完成了实例化,没有达到Lazy loading的效果,有可能造成内存浪费
⽅式⼆:饿汉式(静态代码块)
public class Singleton {
private final static Singleton SINGLETON;
static{
SINGLETON = new Singleton();
}
private Singleton(){
}
public void doAction(){
//TODO 实现你需要做的事
}
public static Singleton getInstance(){
return SINGLETON;
}
}
测试⽤例:
public class Test {
public static void main(String[] args) {
Signleton singleton1 = Instance();
Signleton singleton2 = Instance();
System.out.println("两个singleton对象是否是同⼀个对象:"+ (singleton1 == singleton2) );
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
}
运⾏结果:
两个singleton对象是否是同⼀个对象:true
singleton1的hashCode:366712642
singleton2的hashCode:366712642
这种实现⽅式优缺点和⽅式⼀是⼀样的,也是利⽤了类加载,唯⼀不同的就是将实例化的过程放在了静态代码块中。
⽅式三:懒汉式(线程不安全)
public class Singleton {
private static Singleton singleton;
private Singleton(){
}
public void doAction(){
//TODO 实现你需要做的事
}
public static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
测试代码:
public class Test {
public static void main(String[] args) {
//多线程获取对象,存在线程不安全问题
Thread thread1 = new Thread(new Runnable() {
public void run() {
Singleton singleton1 = Instance();
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
Singleton singleton2 = Instance();
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
});
thread1.start();
thread2.start();
}
}
运⾏结果:
第⼀次运⾏结果:
singleton2的hashCode:1813990537
singleton1的hashCode:1813990537
第⼆次运⾏结果:
singleton1的hashCode:1813990537
singleton2的hashCode:1481479505
从两次运⾏结果来看,我们发现singleton1与singleton2的hashCode存在相同和不想同的两种情况,这就已经证明了这种⽅式的线程不安全性
优点:
1. 起到了Lazy loading效果,适合在单线程环境中使⽤
缺点:
1. 在多线程环境中存在线程不安全问题
⽅式四:懒汉式(⽅法同步)
public class Singleton {
private static Singleton singleton;
private Singleton(){
}
public void doAction(){
//TODO 实现你需要做的事
}
public synchronized static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
测试⽤例(可多做⼏次测试):
public class Test {
public static void main(String[] args) {
//多线程获取对象,线程安全问题
Thread thread1 = new Thread(new Runnable() {
public void run() {
Singleton singleton1 = Instance();
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
Singleton singleton2 = Instance();
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
});
thread1.start();
thread2.start();
}
}
运⾏结果:
第⼀次运⾏结果:
singleton1的hashCode:1947425526
singleton2的hashCode:1947425526
第⼆次运⾏结果:
singleton1的hashCode:1430007319
singleton2的hashCode:1430007319
从两次运⾏结果来看,我们发现singleton1与singleton2的hashCode是⼀样的,说明这种⽅法是线程安全的
优点:
1. 实现了Lazy loading想过
2. 避免了多线程同步问题
缺点:
1. 效率太低,每个线程在执⾏getInstance()⽅法都要进⾏同步。实际上这个⽅法只要执⾏⼀次实例化就⾏,当实例化完成,后⾯的线程是
通不过if判断的
⽅式五:懒汉式(实例化代码同步)
public class Singleton {
private static Singleton singleton;
public Singleton() {
}
public void doAction(){
//TODO 实现你需要做的事
}
public static Singleton getInstance(){
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
单例模式的几种实现方式}
return singleton;
}
}
测试⽤例:
public class Test {
public static void main(String[] args) {
//多线程获取对象,存在线程不安全问题
Thread thread1 = new Thread(new Runnable() {
public void run() {
Singleton singleton1 = Instance();
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
Singleton singleton2 = Instance();
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
});
thread1.start();
thread2.start();
}
}
运⾏结果:
singleton2的hashCode:1813990537
singleton1的hashCode:1430007319
从两次运⾏结果来看,我们发现singleton1与singleton2的hashCode是不相同的,证明这种⽅式是线程不安全的有点:
1. 实现了Lazy loading的现过
2. 相对于第四种的同步,该⽅法的效率得到了提升
缺点:
1. 在多线程环境中存在线程不安全问题
⽅式六:双重检测
public class Singleton {
private static Singleton singleton;
private Singleton(){
}
public void doAction(){
//TODO 实现你需要做的事
}
public static Singleton getInstance(){
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
测试⽤例:
public class Test {
public static void main(String[] args) {
//多线程获取对象,线程安全
Thread thread1 = new Thread(new Runnable() {
public void run() {
Singleton singleton1 = Instance();
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
Singleton singleton2 = Instance();
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
});
thread1.start();
thread2.start();
}
}
运⾏结果:
singleton2的hashCode:1481479505
singleton1的hashCode:1481479505
优点:
1. 线程安全
2. 实现Lazy loading
3. 效率较⾼
⽅式七:静态内部类
public class Singleton {
public Singleton() {
}
public void doAction(){
/
/TODO 实现你需要做的事
}
private static class SingletonInstance{
private final static Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstance.SINGLETON;
}
}
测试⽤例:
public class Test {
public static void main(String[] args) {
//多线程获取对象,线程安全
Thread thread1 = new Thread(new Runnable() {
public void run() {
Singleton singleton1 = Instance();
System.out.println("singleton1的hashCode:"+singleton1.hashCode());
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
Singleton singleton2 = Instance();
System.out.println("singleton2的hashCode:"+singleton2.hashCode());
}
});
thread1.start();
thread2.start();
}
}
运⾏结果:
singleton2的hashCode:1481479505
singleton1的hashCode:1481479505
这种⽅式利⽤了类装载机制来保证初始化实例时只有⼀个线程,静态内部类在Singleton被装载时并不
会⽴即实例化,⽽是在调⽤getInstance()时才会装载静态内部类,从⽽完成Singleton实例化。由于类的静态属性只会在第⼀次加载类的时候进⾏初始化,这⾥我们通过JVM加载类时的线程安全的特性来保证了线程安全

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。