疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java单例模式的实践


 

   

  单例模式是JAVA设计模式中最常用、最重要的设计模式之一。

  最简单的写法是:

  复制代码

  public class TestSingleton {

  private static String ourInstance = null;

  //私有化构造器

  private TestSingleton() {

  }

  //提供静态方法给外部访问

  public static String getOurInstance(){

  if(ourInstance == null){

  ourInstance="单例模式赋值成功!!!";

  System.out.print(ourInstance);

  }

  return ourInstance;

  }

  }

  复制代码

  这种写法的单例模式是线程不安全的,下面用代码来模拟一下多线程并发,代码的执行情况:

  复制代码

  public class Test {

  /**

  * 线程池

  */

  final static ExecutorService threadPool = Executors.newCachedThreadPool();

  /**

  * 并发数

  */

  private final static int CONCURRENT_COUNT = 10;

  /**

  *同步工具类?

  */

  final static CountDownLatch locks = new CountDownLatch(CONCURRENT_COUNT);

  public static void main(String[] args) {

  for (int i = 0; i < CONCURRENT_COUNT; i++) {

  threadPool.execute(new Runnable() {

  @Override

  public void run() {

  locks.countDown();

  TestSinleton.getOurInstance();

  }

  } );

  }

  }

  }

  复制代码

  代码非常简单,用线程池执行CONCURRENT_COUNT 个任务,每个任务执行到

  locks.countDown()

  时被阻塞,当被阻塞的任务数达到CONCURRENT_COUNT个时,所有任务同时往下执行,这样模拟了多个用户并发的场景。(CountDownLatch 的使用方法)

  思考:如果以上写法的单例模式线程安全,那么控制台只会打印一次:单例模式赋值成功!!!

  运行3次程序,查看控制台输出:

  "C:Program FilesJavajdk1.8.0_101injava" ...

  单例模式复制成功!!!单例模式复制成功!!!

  Process finished with exit code 0

  "C:Program FilesJavajdk1.8.0_101injava" ...

  单例模式赋值成功!!!单例模式赋值成功!!!单例模式赋值成功!!!

  Process finished with exit code 1

  "C:Program FilesJavajdk1.8.0_101injava"...

  单例模式赋值成功!!!

  Process finished with exit code 1

  发现并不是想的这样,很容易就出现了变量被多次赋值的情况。所以,以上的单例模式是线程不安全的。

  思考为什么会出现这种情况?

  因为多用户并发操作的情况下,if(ourInstance == null) 可能被同时执行,如果ourInstance为空的话,就会出现多个线程判断(ourInstance == null)为true了。

  修改代码:

  复制代码

  public class TestSinleton {

  private static String ourInstance = null;

  //私有化构造器

  private TestSinleton() {

  }

  //提供静态方法给外部访问

  public static String getOurInstance(){

  if(ourInstance == null){

  synchronized (TestSinleton.class){

  if(ourInstance == null){

  ourInstance="单例模式复制成功!!!";

  System.out.print(ourInstance);

  }

  }

  //ourInstance="单例模式赋值成功!!!";

  //System.out.print(ourInstance);

  }

  return ourInstance;

  }

  }

  复制代码

  第一次判空,大部分线程被挡掉。继续往下是一个synchronized 方法,只允许单线程执行,所以第二次判空就不会存在多个线程同时执行的情况。

  多次运行程序,查看控制台:

  "C:Program FilesJavajdk1.8.0_101injava" ...

  单例模式复制成功!!!

  Process finished with exit code 0

  发现只会打印一次了。