这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 扣丁学堂Java培训之单例设计模式的线程同步

共1条 1/1 1 跳转至

扣丁学堂Java培训之单例设计模式的线程同步

菜鸟
2020-12-24 14:56:55     打赏

单例模式是最常用的设计模式之一,目的是保证一个类只有一个实例。

在项目中的作用:


1、解决因为频繁创建对象,导致资源消耗过大的问题,如:数据库的连接池,连接池用于创建数据库连接,并对连接进行回收使用,能减少数据库连接的创建次数,从而提高效率,但是连接池对象本身在项目中只需要一个,就需要使用单例模式。类似的还有线程池等。

2、项目中能共享的工具类,如Java中的Runtime类能提供各种运行环境系统参数,它就被设计成了单例模式。

实现单例的过程:

1、要保证类只能创建一个对象,就必须隐藏类的构造方法,所以要将构造方法定义为私有的

2、在类中调用构造方法创建对象,定义静态方法用于返回对象。

下面这种单例模式属于饿汉式单例模式,既一开始就将对象实例化。这样的做法会导致性能的降低,一般我们会采用延迟加载的方式,既需要对象时再实例化。

  classHunger{
  //静态的实例
  privatestaticHungerhunger=newHunger();
  //隐藏构造方法
  privateHunger(){}
  //返回静态实例
  publicstaticHungergetInstance(){
  returnhunger;
  }
  }


下面这种是懒汉式单例模式,既开始不实例化对象,到需要该实例时再实例化,提高了运行效率。

  publicclassLazySingleton{
  //静态的实例
  privatestaticLazySingletonsingle=null;
  //隐藏构造方法
  privateLazySingleton(){
  System.out.println("创建LazySingleton对象");
  }
  //返回静态实例
  publicstaticLazySingletongetInstance(){
  if(single==null){
  single=newLazySingleton();
  }
  returnsingle;
  }
  }


线程安全问题:懒汉单例模式在单线程环境没有问题,但在多线程环境下就会出现问题。

执行代码,"创建LazySingleton对象"这句话会输出多次,也就是创建了多个对象。

  for(inti=0;i<100;i++){
  newThread(newRunnable(){
  @Override
  publicvoidrun(){
  System.out.println(LazySingleton.getInstance());
  }}).start();
  }


分析原因:

假设线程1满足getInstance方法中single==null条件后,准备执行创建对象的代码,然后CPU被其它线程抢占,其它线程在getInstance方法中创建对象,然后线程1抢回CPU继续执行刚才未完成的创建对象代码,这样就创建了多个对象。

线程同步问题的解决方法:

1、使用同步方法

publicstaticsynchronizedLazySingletongetInstance(){
if(single==null){
single=newLazySingleton();
}
returnsingle;
}

执行刚才多线程的代码后,我们发现可以解决同步问题,但是同步方法存在的问题是每个线程进入后都会加锁,执行效率低。

2、使用同步代码块配合if使用

publicstaticLazySingletongetInstance(){
if(single==null){
synchronized(LazySingleton.class){
single=newLazySingleton();
}
}
returnsingle;
}


同步块和if语句配合使用,解决了每次都执行上锁导致的性能问题,但是运行代码后我们会发现,多线程同步的问题还是可能出现,原因是多个线程还是可能会同时进入if语句。

3、使用双重判断

在同步块中再添加一次if判断就解决了上面的问题,因为就算多个线程同时进入外层if语句,执行同步块还是要进行一次判断,这样第一个线程创建对象后,后面的线程就不能再创建了。

  publicstaticLazySingletongetInstance(){
  //外层的if主要作用是判断是否需要执行同步块,提高性能
  if(single==null){
  //静态方法中将类作为锁
  synchronized(LazySingleton.class){
  //判断对象是否为空,为空就创建对象
  if(single==null){
  single=newLazySingleton();
  }
  }
  }
  returnsingle;
  }


4、静态内部类

这种方法结合了饿汉式和懒汉式的特点,如果不调用getInstance方法,静态内部类中的创建对象代码不会执行,调用getInstance后才会执行,也就有了懒汉式延迟加载的效果,并且由于对象是直接创建的,还不存在线程同步问题。

  classMySingleton{
  privateMySingleton(){
  }
  privatestaticclassSingletonHelp{
  staticMySingletoninstance=newMySingleton();
  }
  publicstaticMySingletongetInstance(){
  returnSingletonHelp.instance;
  }
  }



总结:单例模式的实现一般有饿汉式、懒汉式和静态内部类等方式,饿汉式创建对象的性能比较低但不存在线程同步问题,懒汉式由于是延迟加载性能更高,但存在线程同步问题,需要使用双重判断解决,静态内部类的方式也能实现单例模式但是代码可读性稍差。

如果项目对性能不敏感推荐使用饿汉式,如果是单线程环境可以使用一般的懒汉式,如果需要多线程则可以使用多重判断的懒汉式或静态内部类实现。

以上就是关于Java开发单例设计模式线程同步的详细介绍,最后想要了解更多可以登录扣丁学堂官网咨询。扣丁学堂是专业的Java培训机构,不仅有专业的老师和与时俱进的课程体系,还有大量的Java视频教程供学员观看学习,想要学好JavaEE的小伙伴抓紧时间行动吧。扣丁学堂java技术交流群:487098661。微信号:codingbb



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]