文章目录
一、加载模式
1.1立即加载/饿汉模式
立即加载就是实用类的时候已经将对象创建完毕。常见的实现办法就是直接new实例化。
Myobject类:
public class Myobject {
public static Myobject myobject = new Myobject();
private Myobject(){
}
public static Myobject getInstance(){
return myobject;
}
}
myThread类:
public class myThread extends Thread {
@Override
public void run() {
System.out.println(Myobject.getInstance().hashCode());
}
}
test类:
public class test {
public static void main(String[] args) {
myThread my = new myThread();
myThread my1 = new myThread();
myThread my2 = new myThread();
my.start();
my1.start();
my2.start();
}
}
1.2 延迟加载/懒汉模式
延迟加载就是在调用get方法时实例才被创建,常见的实现方法就是get()方法中进行new实例化。
public class Myobject {
public static Myobject myobject;
private Myobject() {
}
public static Myobject getInstance() {
if (myobject != null) {
} else {
myobject = new Myobject();
}
return myobject;
}
}
1.3 延迟加载的缺点
在多线程的环境中,上述的实例代码完全就是错误的根本不能实现保持单例的状态。
public class test {
public static void main(String[] args) {
myThread my = new myThread();
myThread my1 = new myThread();
myThread my2 = new myThread();
my.start();
my1.start();
my2.start();
}
}
结果:
1201841772
499131126
499131126
1. 4 延迟加载的解决方案
- 使用synchronzied关键字
缺点:这种方法的运行效率特别低下,是同步运行的,必须等到上一个线程运行结束,才可以继续执行。
public static synchronized Myobject getInstance() {
if (myobject != null) {
} else {
try {
Thread.sleep(3000);
myobject = new Myobject();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return myobject;
}
- 使用同步代码块
同样方法的运行效率低下
public class Myobject {
public static Myobject myobject;
private Myobject() {
}
public static Myobject getInstance() {
synchronized (Myobject.class) {
if (myobject != null) {
} else {
try {
Thread.sleep(3000);
myobject = new Myobject();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return myobject;
}
}
- 针对某些重要的代码进行单独的同步
虽然部分代码上锁,但还是有非线程安全问题,不过方法运行次效率提高了很多。
public static Myobject getInstance() {
if (myobject != null) {
} else {
try {
Thread.sleep(3000);
synchronized (Myobject.class) {
myobject = new Myobject();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return myobject;
}
- 使用DCL双检查锁机制
实现多线程环境中延迟加载单例设计模式
同步代码块里再加一次判断为空的情况,与前面的判断非空构成双检查锁。
public static Myobject getInstance() {
if (myobject != null) {
} else {
try {
Thread.sleep(3000);
synchronized (Myobject.class) {
if(myobject == null)
myobject = new Myobject();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return myobject;
}
二、其他方法实现
2.1 使用静态内之类实现单例模式
public class Myobject {
private static class inObject {
private static Myobject my = new Myobject();
}
private Myobject() {
}
public static Myobject getInstance() {
return inObject.my;
}
}
结果:
376599429
376599429
376599429
2.2 序列化与反序列化的单例模式的实现
静态内置类可以达到线程安全问题,但如果遇到序列化现象时,使用默认的方式得到的结果还是多例的。
主方法:
public class test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Myobject instance = Myobject.getInstance();
FileOutputStream fileOutputStream = new FileOutputStream(new File("myObjectFile.txt"));
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(instance);
fileOutputStream.close();
objectOutputStream.close();
System.out.println(instance.hashCode());
FileInputStream fileInputStream = new FileInputStream(new File("myObjectFile.txt"));
ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
Myobject myobject = (Myobject) inputStream.readObject();
fileInputStream.close();
inputStream.close();
System.out.println(myobject.hashCode());
}
}
使用序列化:
public class Myobject implements Serializable {
private static final long serialVersionUID = 888l;
private static class inObject {
private static Myobject my = new Myobject();
}
private Myobject() {
}
public static Myobject getInstance() {
return inObject.my;
}
}
结果:
2001049719
396180261
- 解决方法:
加入这个方法:
protected Object readResolve(){
System.out.println("调用了一个特殊的方法");
return inObject.my;
}
2.3 使用static代码块实现单例模式
public class Myobject implements Serializable {
private static Myobject myobject = null;
static {
myobject = new Myobject();
}
private Myobject() {
}
public static Myobject getInstance() {
return myobject;
}
}