Java多线程实战之单例模式与多线程的实例详解

1、立即加载/饿汉模式

// 立即加载/饿汉模式

public class MyObject {

private static final MyObject myObject = new MyObject();

private MyObject() {

}

public static MyObject getInstance() {

return myObject;

}

}

立即加载/饿汉模式是在类创建的同时已经创建好一个静态的对象供系统使用,不存在线程安全问题

2、延迟加载/懒汉模式

// 延迟加载/懒汉模式

public class MyObject {

private static MyObject myObject;

private MyObject() {

}

public static MyObject getInstance() {

if (myObject == null) {

myObject = new MyObject();

}

return myObject;

}

}

延迟加载/懒汉模式是在调用方法时实例才被创建,在多线程环境下,会出现取出多个实例的情况,与单例模式的初衷是相背离的

1)、延迟加载/懒汉模式在多线程环境下创建出多个实例:

// 延迟加载/懒汉模式

public class MyObject {

private static MyObject myObject;

private MyObject() {

}

public static MyObject getInstance() {

try {

if (myObject == null) {

TimeUnit.SECONDS.sleep(3);

myObject = new MyObject();

}

} catch (InterruptedException e) {

e.printStackTrace();

}

return myObject;

}

}

public class MyThread extends Thread {

@Override

public void run() {

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

}

}

public class Run {

public static void main(String[] args) {

MyThread myThread = new MyThread();

MyThread myThread2 = new MyThread();

MyThread myThread3 = new MyThread();

myThread.start();

myThread2.start();

myThread3.start();

}

}

运行结果:三次打印的hashCode不完全相等

2)、通过声明synchronized关键字解决线程安全问题:

// 延迟加载/懒汉模式

public class MyObject {

private static MyObject myObject;

private MyObject() {

}

public static synchronized MyObject getInstance() {

try {

if (myObject == null) {

TimeUnit.SECONDS.sleep(3);

myObject = new MyObject();

}

} catch (InterruptedException e) {

e.printStackTrace();

}

return myObject;

}

}

使用synchronized关键字,这种方法的运行效率很低,是同步运行的,下一个线程想要取得对象,则必须等上一个线程释放锁之后,才可以继续执行

3)、使用同步代码块解决线程安全问题:

// 延迟加载/懒汉模式

public class MyObject {

private static MyObject myObject;

private MyObject() {

}

public static MyObject getInstance() {

try {

// 相当于public static synchronized MyObject getInstance()

synchronized (MyObject.class) {

if (myObject == null) {

TimeUnit.SECONDS.sleep(3);

myObject = new MyObject();

}

}

} catch (InterruptedException e) {

e.printStackTrace();

}

return myObject;

}

}

加入同步代码块,这种方法的运行效率也是非常低,和synchronized同步方法一样是同步运行的

4)、针对某些重要的代码进行单独的同步

// 延迟加载/懒汉模式

public class MyObject {

private static MyObject myObject;

private MyObject() {

}

public static MyObject getInstance() {

try {

if (myObject == null) {

TimeUnit.SECONDS.sleep(3);

synchronized (MyObject.class) {

myObject = new MyObject();

}

}

} catch (InterruptedException e) {

e.printStackTrace();

}

return myObject;

}

}

此方法只对实例化对象的关键代码进行同步,从语句的结构上来讲,运行的效率的确得到了提升。但如果是多线程的情况下还是无法解决得到同一个实例对象的结果

5)、使用DCL双检查锁机制

// 延迟加载/懒汉模式

public class MyObject {

private volatile static MyObject myObject;

private MyObject() {

}

public static MyObject getInstance() {

try {

if (myObject == null) {

TimeUnit.SECONDS.sleep(3);

synchronized (MyObject.class) {

if (myObject == null) {

myObject = new MyObject();

}

}

}

} catch (InterruptedException e) {

e.printStackTrace();

}

return myObject;

}

}

使用DCL双检查锁机制,既保证了不需要同步代码的异步执行性,又保证了单例的效果

3、使用静态内部类实现单例模式

public class MyObject {

private static class MyObjectHandler {

private static MyObject myObject = new MyObject();

}

private MyObject() {

}

public static MyObject getInstance() {

return MyObjectHandler.myObject;

}

}

4、使用静态代码块实现单例模式

public class MyObject {

private static MyObject instance = null;

private MyObject() {

}

static {

instance = new MyObject();

}

public static MyObject getInstance() {

return instance;

}

}

5、使用enum枚举实现单例模式

public class MyObject {

public enum MyEnumSingleton {

objectFactory;

private MyObject myObject;

private MyEnumSingleton() {

myObject = new MyObject();

}

public MyObject getInstance() {

return myObject;

}

}

public static MyObject getInstance() {

return MyEnumSingleton.objectFactory.getInstance();

}

}

枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,使用这个特性实现单例设计模式

总结

以上是 Java多线程实战之单例模式与多线程的实例详解 的全部内容, 来源链接: utcz.com/z/348048.html

回到顶部