当前位置: 首页 > news >正文

网站放在香港服务器空间 速度慢百度站长统计工具

网站放在香港服务器空间 速度慢,百度站长统计工具,天津市哪里有做网站广告的,清欢互联网网站建设1 概述 本章的知识点非常重要。在单例模式与多线程技术相结合的过程中,我们能发现很多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。本章的案例也充分说明,线程与某些技术相结合中,我们要考虑的事情会…

 1 概述

        本章的知识点非常重要。在单例模式与多线程技术相结合的过程中,我们能发现很多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。本章的案例也充分说明,线程与某些技术相结合中,我们要考虑的事情会更多。在学习本章的过程中,我们只需要考虑一件事情,那就是:如果使单例模式与多线程结合时是安全、正确的。

2 单例模式与多线程

        在标准的23个设计模式中,单例模式在应用中是比较常见的。但多数常规的该模式教学资料并没有结合多线程技术进行介绍,这就造成在使用结合多线程的单例模式时会出现一些意外。

3 立即加载/饿汉模式

        立即加载指的是,使用类的时候已经将对象创建完毕。常见的实现办法就是new实例化,也被称为“饿汉模式”。

public class MyObject {//立即加载方法 == 饿汉模式private static MyObject object = new MyObject();private MyObject(){}public static MyObject getInstance(){return object;}}
public class MyThread extends Thread{@Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());}
}
public class Run1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}
}

66f314561cdc42398fc9b5d22a3d957d.png

        控制台打印的hashcode是同一个值,说明对象是一个,也就实现了立即加载型单例模式。此代码为立即加载模式,缺点是不能有其他实例变量,因为getInstance()方法没有同步,所以有可能出现非线程安全问题。

4 延迟加载/懒汉模式

        延迟加载就是调用get()方法时,实例才被创建。常见的实现办法就是在get()方法中进行new实例化,也被称为“懒汉模式”。

4.1 延迟加载解析

        先看下面一段代码。

public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){if(object == null){object = new MyObject();}return object;}
}
public class MyThread extends Thread{@Overridepublic void  run(){System.out.println(MyObject.getInstance().hashCode());}
}
public class Run1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}
}

ff9b69c3702340c9b27709e4fa80bd70.png

 4.2 延迟加载的缺点

                前面两个实验虽然使用“立即加载”和“延迟加载”实现了单例模式,但在多线程环境中,“延迟加载”示例中的代码完全是错误的,根本不能保持单例的状态。下面来看如何在多线程环境中结合错误的单例模式创建出多个实例的。 

public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){try {if(object == null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);object = new MyObject();}}catch (InterruptedException e){e.printStackTrace();}return object;}
}
public class MyThread extends Thread{@Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());}
}
public class Run1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}
}

f197c607d54c47b6a385151a86f3ed4c.png

        控制台打印3个不同的hashCode,说明创建了3个对象,并不是单例的。这就是“错误的单例模式”,如何解决呢?

4.3 延迟加载的解决方案 

        (1)声明synchronzied关键字

        既然多个线程可以同时进入getInstance()方法,只需要对getInstance()方法声明synchronzied关键字即可。修改MyObject.java类。

public class MyObject {private static MyObject object;public MyObject() {}synchronized public static MyObject getInstance(){try {if(object == null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);object = new MyObject();}}catch (InterruptedException e){e.printStackTrace();}return object;}
}

326e93f5dd0049f0a4c616c06910e615.png

        此方法在加入同步synchronzied关键字后得到相同实例的对象,但运行效率很低。下一个线程想要取得 对象,必须等待上一个线程释放完锁之后,才可以执行。那换成同步代码块可以解决吗?

(2)尝试同步代码块

        修改MyObject.java类。

public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){try {synchronized (MyObject.class){if(object == null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);object = new MyObject();}}}catch (InterruptedException e){e.printStackTrace();}return object;}
}

         此方法加入同步synchronzied语句块后得到相同实例对象,但运行效率也非常低,和synchronzied同步方法一样是同步运行的。下面继续更改代码,尝试解决这个问题。

(3)针对某个重要的代码进行单独的同步。

修改MyObject.java类。

public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){try {if(object == null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);synchronized (MyObject.class) {object = new MyObject();}}}catch (InterruptedException e){e.printStackTrace();}return object;}
}

d18820343cba46039770f296235eadcc.png

        此方法使同步synchronzied语句块只对实例化对象的关键代码进行同步。从语句的结构上讲,运行效率却是得到了提升,但遇到多线程的情况还是无法得到同一个实例对象。

(4)使用DCL双检查锁机制

public class MyObject {private  volatile static MyObject object;public MyObject() {}public static MyObject getInstance(){try {if(object == null){Thread.sleep(2000);synchronized (MyObject.class){if(object == null){object = new MyObject();}}}}catch (InterruptedException e){e.printStackTrace();}return object;}
}

 使用volatile修改变量object,使该变量在多个线程间可见,另外禁止 object = new MyObject()代码重排序。object = new MyObject()包含3个步骤:

        1、memory = allocate();//分配对象的内存空间

        2、ctorInstance(memory);//初始化对象

        3、object = memory;//设置instance指向刚分配的内存地址

JIT编译器有可能将这三个步骤重新排序。

        1、memory = allocate();//分配对象的内存空间

        2、object = memory;//设置instance指向刚分配的内存地址

        3、ctorInstance(memory);//初始化对象

这时,构造方法虽然还没有执行,但object对象已具有内存地址,即值不是null。当访问object对象中的值时,是当前声明数据类型的默认值。

创建线程类MyThread.java代码如下。

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

     

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

e5c10ed8b5de48eaa67856539d801ca8.png  

        可见,使用DCL双检查锁成功解决了懒汉模式下的多线程问题。DCL也是大多数多线程结合单例模式使用的解决方案。

5 使用静态内置类实现单例模式

        DCL可以解决多线程单例模式的非线程安全问题。还可以使用其他办法达到同样的效果。

public class MyObject {private static class MyObjectHandler{private static MyObject object = new MyObject();}public MyObject() {}public static MyObject getInstance(){return MyObjectHandler.object;}
}

public class MyThread extends Thread{@Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());}
}
public class Run1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}
}

c90168a09bc040ebb2ed202c4c4cad01.png

6 使用static代码块实现单例模式

        静态代码块中的代码在使用类的时候就已经执行,所以可以使用静态代码块的这个特性实现单例模式。

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

public class MyThread extends Thread{@Overridepublic void run(){for (int i = 0; i < 5; i++) {System.out.println(MyObject.getInstance().hashCode());}}
}
public class Run1 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}
}

6197e85b5484485eb782a1342aabf123.png

http://www.hkea.cn/news/382134/

相关文章:

  • 网站开发凭证做什么科目百度推广关键词多少合适
  • 网站正在建设 h5模板新闻热点
  • 龙岗公司网站建设怎么上百度搜索
  • 七米网站建设网站自动推广软件免费
  • 余姚公司做网站跨境电商怎么做
  • 顺义哪有做网站厂家百度快照在哪里找
  • 深圳南山网站建设重庆seo黄智
  • 教育微网站建设我要学电脑哪里有短期培训班
  • 民宿预订网站制作推广方案怎么做
  • 做网站都要掌握什么网页模版
  • 网站怎么做qq微信登陆长沙优化网站哪家公司好
  • 为什么上不了建设银行个人网站漳州网络推广
  • 天津手机网站建站培训代运营公司可靠吗
  • 网站制作的一般步骤长春网站优化平台
  • Python做网站 性能上海seo培训中心
  • 网上投诉平台公众号排名优化
  • 网页模板网站推荐媒体公关是做什么的
  • 泰安的网站建设公司爱站网域名查询
  • 台州椒江网站制作公司广告推销
  • 南康做网站合肥seo招聘
  • 成都网站建设定长沙专业网站制作
  • 有什么网站是python做的如何自己开发一个平台
  • 网站建设标志设计北京网站优化公司
  • 图标使用wordpress杭州seo博客
  • 企业网站如何做推广竞价推广托管公司介绍
  • 网站如何做微信登录seo公司 杭州
  • 中山里水网站建设软文广告案例分析
  • 做外贸是用什么网站做新型网络营销方式
  • 心理咨询网站开发百度手机seo软件
  • 17网站一起做网批seo营销优化