Java多线程编程核心技术4--单例程式与多线程

1.立即加载/饿汉模式

1
2
3
4
5
6
7
8
package singleton;

public class MyThread extends Thread{
 @Override
 public void run() {
  System.out.println(MyObject.getInstance().hashCode());
 }
}

1
2
3
4
5
6
7
8
9
package singleton;

public class MyObject {
 private static MyObject myObject = new MyObject();
 
 public static MyObject getInstance(){
  return myObject;
 }
}

1
2
3
4
5
6
7
8
9
10
11
12
package singleton;

public class Run {
 public static void main(String[] args) {
  MyThread t1 = new MyThread();
  MyThread t2 = new MyThread();
  MyThread t3 = new MyThread();
  t1.start();
  t2.start();
  t3.start();
 }
}

运行结果皆为:

1
11077203

2.延迟加载/懒汉模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package singleton;

public class MyObject2 {
 private static MyObject2 myObject;

 public static MyObject2 getInstance() {
  try {
   if (myObject == null) {
    Thread.sleep(3000);//模拟在创建对象前做一些准备工作
    myObject = new MyObject2();
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return myObject;                  
 }
}

在多线程中,就会出现取出多个实例的情况,与单例模式的初衷是相背离的。运行结果为:
1
2
3
4
5
11077203

14576877

12677476

3.懒汉模式的改进方法

3.1 整个getInstance()方法声明synchronized关键字 ,但是效率太低。

3.2 在getInstance()方法里声明MyObject.class的synchronized同步语句块,其实相当于全部代码被上锁,效率依旧很低。

3.3 在某些重要的代码实施同步语句块,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package singleton;

public class MyObject3 {
 private static MyObject3 myObject;

 public static MyObject3 getInstance() {
  try {
   if (myObject == null) {
    Thread.sleep(3000);
    synchronized(MyObject3.class){
     myObject = new MyObject3();
    }
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return myObject;                  
 }
}

虽然大大提高效率,但是非线程安全,无效。

3.4 使用DCL双检查锁机制 – 推荐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package singleton;

public class MyObject4 {
 private volatile static MyObject4 myObject;

 public static MyObject4 getInstance() {
  try {
   synchronized (MyObject4.class) {
    if (myObject == null) {
     Thread.sleep(3000);
     myObject = new MyObject4();
    }
   }
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return myObject;
 }
}

3.5 静态内部类方式
1
2
3
4
5
6
7
8
9
10
11
package singleton;

public class MyObject5 {
 private static class MyObjectHandler {
  private static MyObject5 myObject = new MyObject5();
 }

 public static MyObject5 getInstance() {
  return MyObjectHandler.myObject;
 }
}

3.6 序列化与反序列化解决:在反序列化中使用readResolve()方法(略)。

3.7 使用static代码块实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
package singleton;

public class MyObject6 {
 private static MyObject6 instance = null;

 static {
  instance = new MyObject6();
 }

 public static MyObject6 getInstance() {
  return instance;
 }
}

3.8 使用枚举数据类型enum:

使用枚举类时,构造方法会被自动调用。(但不要将枚举类进行曝露,应将枚举类包装在一个正常类中,遵守职责单一原则)

作者:有奶喝先森
链接:http://www.jianshu.com/p/442d0e304e76
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。