- 浏览: 546030 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
wa114d:
楼主工作几年了,好厉害
一个面试官对面试问题的分析 -
wobuxiaole:
Good,非常好
30岁前男人需要完成的事 -
小逗逗:
Good,非常好
30岁前男人需要完成的事 -
invincibleLiu:
好帖,要顶!(别投我隐藏啊,这是对BBS最原始一种支持)
Java:synchronized修饰符在静态方法与非静态方法上的区别 -
fayedShih:
第三题,不知道对不对
import java.util.con ...
企业牛逼面试题目 高手进来讨论答题
对于多线程编程来说,同步问题是我们需要考虑的最多的问题,同步的锁什么时候加,加在哪里都需要考虑,当然在不影响功能的情况下,同步越少越好,锁加的越迟越优是我们都必须认同的。DCL(Double Check Lock)就是为了达到这个目的。
DCL简单来说就是check-lock-check-act,先检查再锁,锁之后再检查一次,最后才执行操作。这样做的目的是尽可能的推迟锁的时间。网上普遍举的一个例子是延迟加载的例子。
对上面的例子来说,我们当然也可以把锁加载方法上,那样的话每次获取实例都需要获取锁,但其实对这个instance来说,只有在第一次创建实例的时候才需要同步,所以为了减少同步,我们先check了一下,看看这个instance是否为空,如果为空,表示是第一使用这个instance,那就锁住它,new一个LazySingleton的实例,下次另一个线程来getInstance的时候,看到这个instance不为空,就表示已经创建过一个实例了,那就可以直接得到这个实例,避免再次锁。这是第一个check的作用。
第二个check是解决锁竞争情况下的问题,假设现在两个线程来请求getInstance,A、B线程同时发现instance为空,因为我们在方法上没有加锁,然后A线程率先获得锁,进入同步代码块,new了一个instance,之后释放锁,接着B线程获得了这个锁,发现instance已经被创建了,就直接释放锁,退出同步代码块。所以这就是check-lock-then check。
网上有很多文章讨论DCL的失效问题,我就不赘述了,Java5之后可以通过将字段声明为volatile来避免这个问题。
我推荐一篇很好的文章《用happen-before规则重新审视DCL》,里面讲的非常好。
上面这个是最简单的例子,网上随处可见,双重检查的使用可不只限于单例的初始化,下面我举个实际使用中的例子。
缓存用户信息,我们用一个hashmap做用户信息的缓存,key是userId。
1、 没有锁,即没有②和③,当在代码①处判断userDO为空之后,直接从DB取数据,这种情况下有可能会造成数据的错误。举个例子,A和B两个线程,A线程需要取用户信息,B线程更新这个user,同时把更新后的数据放入map。在没有任何锁的情况下,A线程在时间上先于B线程,A首先从DB取出这个user,随后线程调度,B线程更新了user,并把新的user放入map,最后A再把自己之前得到的老的user放入map,就覆盖了B的操作。B以为自己已经更新了缓存,其实并没有。
2、 没有第二次check,即没有③的情况,在加锁之后立即从DB取数据,这种情况可能会多几次DB操作。同样A和B两个线程,都需要取用户信息,A和B在进入代码①处时都发现map中没有自己需要的user,随后A线程率先获得锁,把新user放入map,释放锁,紧接着B线程获得锁,又从DB取了一次数据放入map。
3、 双重检查,取用户数据的时候,我们首先从map中根据userId获取UserDO,然后check是否取到了user(即user是否为空),如果没有取到,那就开始lock,然后再check一次map中是否有这个user信息(避免其他线程先获得锁,已经往map中放了这个user),没有的话,从DB中得到user,放入map。
4、 在⑤处又判断了一次userDO为空的话就从map中取一次,这是由于此线程有可能在代码③处发现map中已经存在这个userDO,就没有进行④操作。
所以DCL只要记住:check-lock-check-act!
DCL简单来说就是check-lock-check-act,先检查再锁,锁之后再检查一次,最后才执行操作。这样做的目的是尽可能的推迟锁的时间。网上普遍举的一个例子是延迟加载的例子。
public class LazySingleton { private static volatile LazySingleton instance; public static LazySingleton getInstantce() { if (instance == null) { synchronized (LazySingleton.class) { if (instance == null) { instance = new LazySingleton(); } } } return instance; } }
对上面的例子来说,我们当然也可以把锁加载方法上,那样的话每次获取实例都需要获取锁,但其实对这个instance来说,只有在第一次创建实例的时候才需要同步,所以为了减少同步,我们先check了一下,看看这个instance是否为空,如果为空,表示是第一使用这个instance,那就锁住它,new一个LazySingleton的实例,下次另一个线程来getInstance的时候,看到这个instance不为空,就表示已经创建过一个实例了,那就可以直接得到这个实例,避免再次锁。这是第一个check的作用。
第二个check是解决锁竞争情况下的问题,假设现在两个线程来请求getInstance,A、B线程同时发现instance为空,因为我们在方法上没有加锁,然后A线程率先获得锁,进入同步代码块,new了一个instance,之后释放锁,接着B线程获得了这个锁,发现instance已经被创建了,就直接释放锁,退出同步代码块。所以这就是check-lock-then check。
网上有很多文章讨论DCL的失效问题,我就不赘述了,Java5之后可以通过将字段声明为volatile来避免这个问题。
我推荐一篇很好的文章《用happen-before规则重新审视DCL》,里面讲的非常好。
上面这个是最简单的例子,网上随处可见,双重检查的使用可不只限于单例的初始化,下面我举个实际使用中的例子。
缓存用户信息,我们用一个hashmap做用户信息的缓存,key是userId。
public class UserCacheDBService { private volatile Map<Long, UserDO> map = new ConcurrentHashMap<Long, UserDO>(); private static Object mutex = new Object(); /** * 取用户数据,先从缓存中取,缓存中没有再从DB取 * @param userId * @return */ public UserDO getUserDO(Long userId) { UserDO userDO = map.get(userId); if(userDO == null) { ① check synchronized(mutex) { ② lock if (!map.containsKey(userId)) { ③ check userDO = getUserFromDB(userId); ④ act map.put(userId, userDO); } } } if(userDO == null) { ⑤ userDO = map.get(userId); } return userDO; } private UserDO getUserFromDB(Long userId) { // TODO Auto-generated method stub return null; } }三种做法:
1、 没有锁,即没有②和③,当在代码①处判断userDO为空之后,直接从DB取数据,这种情况下有可能会造成数据的错误。举个例子,A和B两个线程,A线程需要取用户信息,B线程更新这个user,同时把更新后的数据放入map。在没有任何锁的情况下,A线程在时间上先于B线程,A首先从DB取出这个user,随后线程调度,B线程更新了user,并把新的user放入map,最后A再把自己之前得到的老的user放入map,就覆盖了B的操作。B以为自己已经更新了缓存,其实并没有。
2、 没有第二次check,即没有③的情况,在加锁之后立即从DB取数据,这种情况可能会多几次DB操作。同样A和B两个线程,都需要取用户信息,A和B在进入代码①处时都发现map中没有自己需要的user,随后A线程率先获得锁,把新user放入map,释放锁,紧接着B线程获得锁,又从DB取了一次数据放入map。
3、 双重检查,取用户数据的时候,我们首先从map中根据userId获取UserDO,然后check是否取到了user(即user是否为空),如果没有取到,那就开始lock,然后再check一次map中是否有这个user信息(避免其他线程先获得锁,已经往map中放了这个user),没有的话,从DB中得到user,放入map。
4、 在⑤处又判断了一次userDO为空的话就从map中取一次,这是由于此线程有可能在代码③处发现map中已经存在这个userDO,就没有进行④操作。
所以DCL只要记住:check-lock-check-act!
发表评论
-
ConcurrentHashMap在jdk1.7和jdk1.8中的不同
2021-12-02 17:30 0https://blog.csdn.net/qq_418849 ... -
CallableAndFuture
2012-07-24 11:31 1174import java.util.concurrent.Cal ... -
CountDownLatch
2012-07-24 11:00 1175concurrent包里面的CountDownLatch其实可 ... -
认识理解Java中native方法
2011-11-02 16:35 2358Java不是完美的,Java的不足除了体现在运行速度 ... -
java 数组复制:System.arrayCopy 深入解析
2011-11-02 10:02 4168转载:http://happyjin2010.it ... -
equals hashcode 深度分析
2011-07-14 13:17 11451.hashcode是用来查找的,如果你学过数据结构就应该知道 ... -
java proxy
2011-07-12 16:31 936代理?就是别人帮你管理叫代理. 举个例子 你是家里的主人, ... -
关于 JVM 命令行标志您不知道的 5 件事(来自IBM)
2010-11-29 17:10 963JVM 是多数开发人员视为理所当然的 Java 功能和性能背后 ... -
关于 Java Collections API 您不知道的 5 件事,第 1 部分(转自IBM)
2010-11-29 16:58 982对于很多 Java 开发人员 ... -
java线程安全总结(转载jameswxx)
2010-11-29 12:50 1364最近想将java基础的一些 ... -
说说new Integer和Integer.valueOf(转载jameswxx)
2010-11-29 12:23 1639看看这两个语句 Integer a=new Integer ... -
优化JVM参数提高eclipse运行速度
2010-11-26 16:13 882性能优化从身边做起。 首先建立评估体系,将workspac ... -
主题:一次Java垃圾收集调优实战
2010-11-26 15:29 11261 资料 •JDK5.0垃圾收集优化之--Don't Paus ... -
通过GC输出分析内存泄露问题
2010-11-26 15:13 1023SIP5.0以后服务的请求量爆发性增长,因此也暴露了原来没有暴 ... -
15种提高系统伸缩性和性能的最佳实践
2010-11-25 16:00 9931, 提高系统性能, 需要尽早做性能剖析, 而且要经常做.当项 ... -
JVM调优总结(一)-- 一些概念
2010-11-25 15:00 891数据类型 Java虚拟机中,数据类型可以分为两类:基本 ... -
JVM原理学习笔记一
2010-06-11 16:22 903最近在阅读 《Inside the J ... -
ImportDataFromMySQLToOracle
2009-12-10 10:42 1340import java.sql.Connection; im ... -
Merge two Hashtable<String, Integer>
2009-12-03 14:50 1360private static Hashtable< ... -
TreeMap 排序重写
2009-12-03 14:40 4419import java.util.Comparator; i ...
相关推荐
双重检查锁(Double-Checked Locking, DCL)是一种在多线程环境中用于实现懒加载(lazy loading)的设计模式。它通过两次检查来确定是否需要获取锁,从而避免不必要的同步操作,提高程序性能。然而,DCL的实现并不像表面...
DCL(Double-checked locking)是Java双重检查加锁单例模式的一种实现方法。它使用了synchronized关键字来确保线程安全,但是这也会带来性能损失。DCL看起来是一个聪明的优化,但是它却不能保证正常工作。 在多线程...
在这个主题下,“DCL常用设计方法”通常指的是如何在Java等编程语言中实现Double-Check Locking(双重检查锁定)和其他相关的设计模式来优化并发性能。以下将详细介绍DCL及其相关的知识点。 1. 双重检查锁定...
用VB的Form直接生成DCL对话框程序极其调用的LSP文件 能自动对DCL对话框中的参数进行读取和赋值,并输出 使用步骤: 一、在VB中绘制好表单Form 注意:排列的时候尽量一行的Top坐标相同,这样能保证在同一行 二、将...
在AutoCAD的二次开发中,DCL(Dialog Create Language)对话框是不可或缺的一部分,它允许用户自定义界面,提高工作效率,增强软件的用户友好性。本自学教程将深入探讨DCL对话框的创建、使用以及与AutoLISP或Visual ...
- **语义检查**:提供了不同级别的语义检查,帮助开发者检测定义文件中的潜在问题。 - **预览功能**:在VisualLISP环境中可以预览对话框的外观,方便调试和调整设计。 #### 七、注意事项 - **版权信息**:本教程...
根据提供的文件信息,我们可以提取并总结出关于DCL-33A指示控制器的相关知识点: ### DCL-33A 指示控制器介绍 #### 一、产品概述 DCL-33A是一款用于安装在导轨上的指示控制器,其设计符合一定的规格要求。该控制器...
**DCL对话框基础** DCL(Dialog Control Language)对话框是AutoCAD中的一种用户界面元素,用于创建自定义的交互式窗口,使用户能够更方便地输入数据、选择选项或执行特定操作。对话框在现代软件开发中扮演着至关...
本文将详细讨论四种常见的单例实现方式:饿汉模式、懒汉模式、双重检查锁定(DCL)单例模式以及枚举单例。 1. **饿汉模式**: 饿汉模式是在类加载时就完成了实例化,避免了线程同步问题。这种方式简单且安全,但...
【DCL代码生成器 (DCG)】是一个专门针对CAD软件的工具,主要用途是自动生成LISP(LISt Processing)代码。在CAD环境中,LISP语言被广泛用于编写脚本和扩展功能,因为它允许用户定制和自动化各种设计任务。DCG通过...
在CAD环境下,利用LISP做对话框,方便数据输入。
AUTOLISP@DCL基础篇(全)铁道出版社(推荐)
AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.AutoLISP_DCL.
第3篇(第12~21章)为autolisp与dcl对话框整合应用,主要介绍了dcl的基础知识、dcl对象属性的定义速查、autolisp掌控dcl的关键技巧;还介绍了编辑框、按钮和文字、切换开关、单选按钮、列表框、下拉菜单、图像,图像...
DCL(Dialog Control Language)驱动程序是一种用于创建图形用户界面(GUI)的编程语言,主要在Autodesk AutoCAD等软件中使用。它允许用户通过图形化的对话框与应用程序交互,而不是仅通过命令行输入。本PPT课件详细...
AutoLISP和DCL是两种在AutoCAD环境中广泛使用的编程语言,主要用于扩展和自定义AutoCAD的功能。AutoLISP是一种基于LISP语言的方言,专为AutoCAD设计,而DCL(Design Center Language)则是用于创建用户界面和对话框...
根据提供的标题、描述以及部分上下文内容,我们可以推断出这本书《AutoCAD程序设计魔法书》主要关注的是AutoCAD中的AutoLISP与DCL(Dialog Control Language)编程基础。尽管提供的部分内容似乎没有实质性的信息,但...
在这个“COBOL学习例子(包含DCL脚本)”压缩包中,我们可以找到一系列关于如何使用COBOL和DCL的实践教程。这些例子将帮助初学者理解和掌握这两种技术的核心概念。 1. **COBOL基础**: COBOL的语法结构清晰,主要由...