机器学习和数据挖掘的推荐书单

机器学习和数据挖掘的推荐书单 本文作者: 伯乐在线 - 天才白痴梦 。 有了这些书,再也不愁下了班没妹纸该咋办了。慢慢来,认真学,揭开机器学习和数据挖掘这一神秘的面纱吧! 《机器学习实战》: 本书第一部分主要介绍机器学习基础,以及如何利用算法进行分类,并逐步介绍了多种经典的监督学习算法,如k近邻算法、朴素贝叶斯算法、Logistic回 归算法、支持向量机、AdaBoost集成方法、基于树的回归算法和分类回归树(CART)算法等。第三部分则重点介绍无监督学习及其一些主要算法:k均 值聚类算法、Apriori算法、FP-Growth算法。第四部分介绍了机器学习算法的一些附属工具。 全书通过精心编排的实例,切入日常工作任务,摒弃学术化语言,利用高效的可复用Python代码来阐释如何处理统计数据,进行数据分析及可视化。通 过各种实例,读者可从中学会机器学习的核心算法,并能将其运用于一些策略性任务中,如分类、预测、推荐。另外,还可用它们来实现一些更高级的功能,如汇总 和简化等。 之前看过一部分这本书,但是实习工作涉及到用Java代码处理数据,所以暂时先搁一下,目前正在李航的那本书。 《数据挖掘-实用机器学习技术》: 本书介绍数据挖掘的基本理论与实践方法。主要内容包括:各种模型(决策树,关联规则、线性模型、聚类、贝叶斯网以及神经网络)以及在实践中的运用,所存任 缺陷的分析。安全地清理数据集、建立以及评估模型的预测质量的方法,并且提供了一个公开的数据挖掘工作平台Weka。Weka系统拥有进行数据挖掘仟务的 图形用户界面,有助于理解模型,是一个实用并且深受欢迎的工具。 《数据挖掘:概念与技术》: 本书全面地讲述数据挖掘领域的重要知识和技术创新。在第1版内容相当全面的基础上,第2版展示了该领域的最新研究成果,例如挖掘流、时序和序列数据以及挖 掘时间空间、多媒体、文本和Web数据。本书可作为数据挖掘和知识发现领域的教师、研究人员和开发人员的一本必读书。 《统计学习基础 数据挖掘、推理与预测》:尽管应用的是统计学方法,但强调的是概念,而不是数学。许多例子附以彩图。《统计学习基础:数据挖掘、推 理与预测》内容广泛,从有指导的学习(预测)到无指导的学习,应有尽有。包括神经网络、支持向量机、分类树和提升等主题,是同类书籍中介绍得最全面的。计 算和信息技术的飞速发展带来了医学、生物学、财经和营销等诸多领域的海量数据。理解这些数据是一种挑战,这导致了统计学领域新工具的发展,并延伸到诸如数 据挖掘、机器学习和生物信息学等新领域。 《机器学习》 (Mitchell):展示了机器学习中核心的算法和理论,并阐明了算法的运行过程。《机器学习》综合了许多的研究成果,例如统计学、人工智能、哲学、信 息论、生物学、认知科学、计算复杂性和控制论等,并以此来理解问题的背景、算法和其中的隐含假定。《机器学习》可作为计算机专业 本科生、研究生教材,也 可作为相关领域研究人员、教师的参考书。 《统计学习方法》: 本书全面系统地介绍了统计学习的主要方法,特别是监督学习方法,包括感知机、k近邻法、朴素贝叶斯法、决策树、逻辑斯谛回归与最大熵模型、支持向量机、提 升方法、em算法、隐马尔可夫模型和条件随机场等。除第1章概论和最后一章总结外,每章介绍一种方法。叙述从具体问题或实例入手,由浅入深,阐明思路,给 出必要的数学推导,便于读者掌握统计学习方法的实质,学会运用。为满足读者进一步学习的需要,书中还介绍了一些相关研究,给出了少量习题,列出了主要参考 文献。 《机器学习导论》:对机器学习的定义和应用实例进行了介绍,涵盖了监督学习。贝叶斯决策理论。参数方法、多元方法、维度归约、聚类、非参数方法、决策树。线性判别式、多层感知器,局部模型、隐马尔可夫模型。分类算法评估和比较,组合多学习器以及增强学习等。 《机器学习及其应用》:全书共分14章,内容分别涉及因果推断、流形学习与降维、迁移学习、类别不平衡学习、演化聚类、多标记学习、排序学习、半监督学习等技术和协同过滤、社区推荐、机器翻译等应用,以及互联网应用对机器学习技术需求的探讨。 《模式分类》第二版:除了保留了第1版的关于统计模式识别和结构模式识别的主要内容以外,读者将会发现新增了许多近25年来的新理论和新方法,其中包括神经网络、机器学习、数据挖掘、进化计算、不变量理论、隐马尔可夫模型、统计学习理论和支持向量机等。 《推荐系统实践》:过大量代码和图表全面系统地阐述了和推荐系统有关的理论基础,介绍了评价推荐系统优劣的各种标准(比如覆盖率、满意度)和方法(比如AB测试),总结了当今互联网领域中各种和推荐有关的产品和服务。 《深入搜索引擎:海量信息的压缩、索引和查询》:理论和实践并重,深入浅出地给出了海量信息数据处理的整套解决方案,包括压缩、索引和查询的方方面面。其最大的特色在于不仅仅满足信息检索理论学习的需要,更重要的是给出了实践中可能面对的各种问题及其解决方法。 《概率论与数理统计》:这本书不用过多介绍了吧,普遍大学里大一时期的教科书,只恨当年没听课啊,现在正在慢慢啃。。。 《大数据:互联网大规模数据挖掘与分布式处理》:主要内容包括分布式文件系统、相似性搜索、搜索引擎技术、频繁项集挖掘、聚类算法、广告管理及推荐系统。 《Web数据挖掘》: 信息检索领域的书籍,该书深入讲解了从大量非结构化Web数据中提取和产生知识的技术。书中首先论述了Web的基础(包括Web信息采集机制、Web标引 机制以及基于关键字或基于相似性搜索机制),然后系统地描述了Web挖掘的基础知识,着重介绍基于超文本的机器学习和数据挖掘方法,如聚类、协同过滤、监 督学习、半监督学习,最后讲述了这些基本原理在Web挖掘中的应用。《Web数据挖掘》为读者提供了坚实的技术背景和最新的知识。 《数据之巅》:对大数据追根溯源,提出当前信息技术的发展,已经让中国获得了后发优势,中国要在大数据时代的全球竞争中胜出,必须把大数据从科技符号提升成为文化符号,在全社会倡导数据文化。 《深入浅出统计学》:本书涵盖的知识点包括:信息可视化、概率计算、几何分布、二项分布及泊松分布、正态分布、统计抽样、置信区间的构建、假设检验、卡方分布、相关与回归等等,完整涵盖AP考试范围。 《矩阵分析》: 本书从数学分析的角度论述矩阵分析的经典方法和现代方法,取材新,有一定的深度,并给出在多元微积分、复分析、微分方程、量优化、逼近理论中的许多重要应 用。主要内容包括:特征值、特征向量和相似性,酉等价和正规矩阵,标准形,Hermite矩阵和对称矩阵,向量范数和矩阵范数,特征值和估计和扰动,正定 矩阵,非负矩阵。

October 26, 2015 · 1 min · 54 words · Jimmy

JS规则-使用js的最佳实践

1. JS应该放到 .js 文件中 “额,只有那么几行而已…”,是的,我的意思是所有的 JS 都应该放在.js文件中。为什么呢?因为这有助于可读性,节省带宽。行内 JavaScript 在每次页面加载时都会重新下载,相反的,单独的.js文件则会被缓存起来。正如你所看到的,这个规则有助于支持如下一长串的其他规则。这就是为什么它的规则# 1。 2. JS 应该是静态的 我看到过很多程序员喜欢动态的使用JavaScript。他们喜欢像使用服务器端语言如C#, Ruby, Java那样来动态的使用JavaScript。千万不要这么做。你失去了代码着色、语法高亮显示和智能感知的支持。记住,JavaScript 应该属于一个.js文件(见规则 #1)。 然而,使用JSON引入动态行为。我把这称为JavaScript配置对象模式。具体方法如下:把JSON注入到你应用程序的头部,并根据业务逻辑 的需要利用这些数据。你可能会想:“嘿,这违背了规则 #1”。我把 JSON 看作是数据,而不是代码,所以我破例,为了支持静态的、单独的JavaScript文件。 StackOverflow 使用的这种模式,Google 也是。 3. JS 应该被压缩 压缩可以减小文件体积,从而提升页面加载速度。记住,性能也是一项功能。因为,为了压缩,你需要把 JS 放到一个单独的文件中(见规则 #1)。压缩JS曾经很麻烦,但现在完全是简单自动化的。有一打的方式可以做到,而Gulp和gulp-uglify是一种低摩擦和自动化的办法。 4. JS 应该位于页面底部 如果你把标签放在中,它会阻碍页面渲染。位于中的脚本必须在页面显示前加载,因此把放在底部的 前面可以先显示页面,而不用等 JS 文件下载完毕。这有助于提升感知性能。如果你的JavaSctipe必须位于中,可以考虑使用 jQuery 的$(document).ready这样你的脚本可以等到 DOM 加载完毕后再执行。 5. JS 应该实时的 Linted Linting 遵循代码风格、发现错别字、有助于避免错误。有很多这样的工具,我建议使用ESLint。你可以使用 Gulp 的gulp-eslint来运行它。Gulp 可以查看你所有的 JS 文件,并在你每次保存的时候运行 linter。另外,你需要把你的 JS 代码放在单独的 .js 文件中才能运行 linter 。 ...

October 13, 2015 · 1 min · 152 words · Jimmy

使用scrapy写爬虫

使用scrapy写爬虫 一开始想在windows环境下安装scrapy,无奈安装多次都失败,转向linux linux自带python2.7 因此只需要安装scrapy模块就行 先用pip安装Scrapy 失败 于是安装easy_install 命令行 sudo apt-get install python-setuptools sudo easy_install Scrapy 出现错误,搜索知道必须使用python的dev版本 于是 sudo apt-get install python-dev 再次 sudo easy_install Scrapy 安装成功 然后安装mongodb sudo easy_instal pymongo

August 4, 2015 · 1 min · 30 words · Jimmy

spacevim安装与使用

安装 安装spacevim的前提是安装好vim,一般linux系统自带 #redhat系列 sudo yuminstall vim / sudo dnfinstall vim #debian系列 sudo aptinstall vim #或者 sudo apt-getinstall vim 安装spacevim curl -sLf https://spacevim.org/install.sh | bash 启动spacevim,等待下载插件 vim test.txt 使用 #打开目录 vim path #右边就会出现目录,移动光标到目录上,按回车键,就能进入目录;移动到文件上,按回车键就能打开文件;按退格键能返回上级目录 #切换工程目录区与编辑的文件 <ctrl+tab>#创建文件 在工程区移动到文件夹下,按<shift+n>,下方提示栏就会出现提示,输入文件名,回车,创建文件 #删除文件 在工程区移动到文件夹下,按,下方提示栏就会出现提示,是否要删除,输入yes删除

August 3, 2015 · 1 min · 37 words · Jimmy

PHP字符串常用函数学习

PHP字符串常用函数学习 <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <body> </body> </head> </html> <?php echo '1 int crc32(string str),产生32位长的crc多项式,比如crc32("helllo")<br/>'; echo crc32 ("jkkajjjk\n"); echo '<br/>'; echo '2 string bin2hex(string str) , 把二进制转换为十六进制,比如bin2hex("helloworld")<br/>'; echo bin2hex("hello world"); echo '<br/>'; echo '3 string chop(string str),移除str后面多余的空白,返回新的字符串<br/>'; echo 'kkkj l '; echo 'hahah'; echo chop("kkkj l "); echo 'hahah'; echo '<br/>'; echo '4 string chr(int ascii),返回指定ascii码表示的字符,如chr(100)<br/>'; echo chr(100); echo '<br/>'; echo '5 int ord(string str),返回str字符串第一个字符的ascii码,如ord("d"),<br/>'; echo ord("d"); echo "<br/>"; echo '6 string chunk_split(string str,int chunklen, string end),把字符串没隔一定数目就分割,如chunk_split("jasdjkasjdkasadas",5,"|"),就是把字符串每5个字符用|分割<br/>'; echo chunk_split("jasdjkasjdkasadas",5,"|"); echo '<br/>'; echo '7 string crypt(string str,string salt),单向加密,无解密函数~'; echo '<br/>'; echo crypt("hello world","kk"); echo '<br/>'; echo ' CRYPT_STD_DES - 基于标准 DES 算法的散列使用 "./0-9A-Za-z" 字符中的两个字符作为盐值。在盐值中使用非法的字符将导致 crypt() 失败。 CRYPT_EXT_DES - 扩展的基于 DES 算法的散列。其盐值为 9 个字符的字符串,由 1 个下划线后面跟着 4 字节循环次数和 4 字节盐值组成。它们被编码成可打印字符,每个字符 6 位,有效位最少的优先。0 到 63 被编码为 "./0-9A-Za-z"。在盐值中使用非法的字符将导致 crypt() 失败。 CRYPT_MD5 - MD5 散列使用一个以 $1$ 开始的 12 字符的字符串盐值。 CRYPT_BLOWFISH - Blowfish 算法使用如下盐值:“$2a$”,一个两位 cost 参数,“$” 以及 64 位由 “./0-9A-Za-z” 中的字符组合而成的字符串。在盐值中使用此范围之外的字符将导致 crypt() 返回一个空字符串。两位 cost 参数是循环次数以 2 为底的对数,它的范围是 04-31,超出这个范围将导致 crypt() 失败。 CRYPT_SHA256 - SHA-256 算法使用一个以 $5$ 开头的 16 字符字符串盐值进行散列。如果盐值字符串以 “rounds=<N>$” 开头,N 的数字值将被用来指定散列循环的执行次数,这点很像 Blowfish 算法的 cost 参数。默认的循环次数是 5000,最小是 1000,最大是 999,999,999。超出这个范围的 N 将会被转换为最接近的值。 CRYPT_SHA512 - SHA-512 算法使用一个以 $6$ 开头的 16 字符字符串盐值进行散列。如果盐值字符串以 “rounds=<N>$” 开头,N 的数字值将被用来指定散列循环的执行次数,这点很像 Blowfish 算法的 cost 参数。默认的循环次数是 5000,最小是 1000,最大是 999,999,999。超出这个范围的 N 将会被转换为最接近的值。 '; if (CRYPT_STD_DES == 1) { echo "Standard DES: ".crypt("hello world")."\n<br />"; } else { echo "Standard DES not supported.\n<br />"; } if (CRYPT_EXT_DES == 1) { echo "Extended DES: ".crypt("hello world")."\n<br />"; } else { echo "Extended DES not supported.\n<br />"; } if (CRYPT_MD5 == 1) { echo "MD5: ".crypt("hello world")."\n<br />"; } else { echo "MD5 not supported.\n<br />"; } if (CRYPT_BLOWFISH == 1) { echo "Blowfish: ".crypt("hello world"); } else { echo "Blowfish DES not supported."; } echo '<br/>'; echo ' 8 array explode (string separator, string string [, int limit]),传回一个字符串的数组,以参数 separator为界线将参数 string切开,如果有设定参数 limit,则传回的数组最多将会包含 limit个元素,而最后一个元素将会包含 string全部剩余的部份。<br/>'; $pizza="haa kkkk kllom lljjijj iioo "; $pieces=explode(" ",$pizza); foreach($pieces as $val){ echo $val; } echo '<br/>'; echo '9 string implode (string glue, array pieces) 以参数glue将数组pieces的各个元素结合起来成字符串返回.与join(string glue,array pieces)相同用法<br/>'; echo implode (":", $pieces); echo '<br/>'; echo '10 array split (string pattern, string string [, int limit]),以正则把字符串切开 ' ?>

July 19, 2015 · 2 min · 340 words · Jimmy

机器学习实战-学习笔记之NaiveBayes

项目地址:http://github.com/jimersylee/MachineLearningAction 基于概率论的分类方法 朴素贝叶斯 使用概率分布进行分类 学习朴素贝叶斯分类器 解析RSS源数据 使用朴素贝叶斯来分析不同地区的态度 朴素贝叶斯 优点:在数据较少的情况下仍然有效,可以处理多类别问题 缺点:对于输入数据的准备方式较为敏感 使用数据类型:标称型数据 贝叶斯决策理论的核心思想–即选择具有最高概率的决策 条件概率 P(A|B)= P(AB)−−−−−−\P(B) 使用贝叶斯准则,进行条件与结果的互换计算 已知P(A|B),求P(B|A) P(B|A)= P(A|B)P(B)−−−−−−−−−−\P(A) 推导 给定某个点(x,y),那么该点来自ci的概率为P(ci|x,y) P( ci |x,y)= P(x,y|ci)P(ci)−−−−−−−−−−−−\P(x,y) 结论 如果P(c1|x,y)>P(c2|x,y),那么(x,y)属于c1如果P(c2|x,y)>P(c1|x,y),那么(x,y)属于c2 使用朴素贝叶斯进行文档分类 朴素贝叶斯是贝叶斯分类器的一个扩展,是用于文档分类的常用算法 朴素贝叶斯的一帮过程 收集数据:可以使用任何方法,本章使用RSS源 准备数据:需要数值型或者布尔型数据 分析数据:有大量特征时,绘制特征作用不大,此时使用直方图效果较好 训练算法:计算不同的独立特征的条件概率 测试算法:计算错误率 使用算法:一个常见的朴素贝叶斯应用是文档分类.可以在任意的分类场景中使用朴素贝叶斯分类器,不一定非要是文本. 假设词汇表有1000个单词,要得到好的概率分布,需要足够的样本,假设样本数为N 由统计学知,如果每个特征需要N个样本,那么对于x个特征,将需要Nx个样本 对于1000个特征的词汇表将需要 N1000 个样本,可以看到,所需要的样本数会随着特征数目的增大而迅速增长 如果特征之间项目独立,那么样本数就能从 N1000 减少到N*1000.所谓独立,指的是 统计学上的独立,即一个特征或者单词出现的可能性与它和其他相邻单词没关系 示例:使用Python进行恶意留言分类 当论坛中用户发表评论时,总会存在一些恶意言论,如何识别是否为恶意评论,而不让其发送呢? 准备数据:从文本中构建词向量,详见bayes.py中的 createVocabList setOfWords2Vec 训练算法:从词向量计算概率 重写贝叶斯准则,将之前的x,y替换为w,粗体w表示一个向量,即它是由多个数值组成.在这个例子中,数值个数与词汇表中的词个数相同 P( ci |w)= P(w|ci)P(ci)−−−−−−−−−−\P(w) 如何计算?首先通过类别i(侮辱性或者非侮辱性留言)中的文档数除以总的文档数的计算概率p( ci ),接下来计算P( ci |w),这里就用到了朴素贝叶斯假设 如果将w展开为一个个独立特征,那么可以将上述概率写做P(w0,w1,…,wN|ci).这里假设所有事件都独立,它意味着可以使用P(w0|ci)P(w1|ci)…P(wN|ci)来计算概率,这极大地简化了计算过程 该函数的伪代码如下 计算每个类别中的文档数目 对每篇训练文档: 对每个类别: 如果词条出现文档中->增加该词条的计数值 增加所有词条的计数值 对每个类别: 对每个词条: 将该词条的数目除以总词条数目得到条件概率 返回每个类别的条件概率 ...

May 22, 2015 · 1 min · 85 words · Jimmy

设计模式之模板方法模式

模板方法模式 模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤 这个模式是用来创建一个算法的模板.什么是模板?模板就是一个方法.更具体地说,这个方法将算法定义为一组步骤,其中的任何步骤都可以是抽象的,由子类负责实现.这可以确保算法的结构保持不变,同时由子类提供部分实现. 快速搞定咖啡和茶的类 /** * 这是我们的咖啡类,用来煮咖啡 */publicclassCoffee { voidprepareRecipe(){ boilWater(); brewCoffeeGrinds(); pourInCup(); addSugarAndMilk(); } privatevoidaddSugarAndMilk() { System.out.println("addSugarAndMilk"); } privatevoidpourInCup() { System.out.println("pourInCup"); } privatevoidbrewCoffeeGrinds() { System.out.println("brewCoffeeGrinds"); } privatevoidboilWater() { System.out.println("boilWater"); } } publicclassTea { voidprepareRecipe(){ boilWater(); steepTeaBag(); pourInCup(); addLemon(); } privatevoidaddLemon() { System.out.println("addLemon"); } privatevoidpourInCup() { System.out.println("pourInCup"); } privatevoidsteepTeaBag() { System.out.println("steepTeaBag"); } privatevoidboilWater() { System.out.println("boilWater"); } } 请注意,boilWater()和pourCup()这两个方法完全一样,也就是说这里出现了重复的代码 在这里,茶和咖啡是如此的相似,可以提取基类 注意两份冲泡法都采用了相同的算法 抽象prepareRecipe() voidprepareRecipe(){ boilwater(); brew(); pourInCup(); addCondiments(); } prepareRecipe()就是我们的模板方法 它是一个方法 它用作一个算法的模板,在这个例子中,算法是用来制作咖啡饮料的 在这个模板中,算法内的每一个步骤都被一个方法代表了 某些方法是由这个类(也就是超类)处理的 某些方法是由子类处理的 需要由子类提供的方法,必须在超类中声明为抽象 优劣对比 不好的茶和咖啡的实现 ...

May 22, 2015 · 1 min · 100 words · Jimmy

设计模式之适配器模式

适配器模式与外观模式 适配器模式 需求 现在已经存在IDuck接口,Turkey接口,假设你缺鸭子对象,想用一些火鸡对象来冒充.显而易见,因为火鸡的接口不同,所以我们不能公然拿来用,那么写个适配器吧 FAQ 一个适配器需要做多少适配工作? 实现一个适配器所需要进行的工作,和目标接口的大小成正.如果不用适配器,你就必须改写客户端的代码来调用这个新的接口.相比之下,使用适配器成本更少 一个适配器只能封装一个类吗? 虽然大多数的适配器模式所采取的例子都是让一个适配器包装一个被适配者,但还是会有状况需要让一个适配器包装多个被适配者.这设计到另一个模式,被称为外观模式(Facade Pattern),人们常常将外观模式和适配器模式混为一谈,本章稍后对此详细说明 万一我的系统中新旧并存,是不是不使用适配器更好 可以创建一个双向的适配器,支持两边的接口.这样,这个适配器可以当做旧的接口,或者当做新的接口使用 外观模式 外观模式提供了一个统一的接口,用来访问子系统中的一群接口.外观定了一个高层接口,让子系统更容易使用. 外观模式的意图是提供一个简单的接口,好让一个子系统更易于使用 要点 当需要使用一个现有的类而其接口并不符合你的需求时,就使用适配器 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观 适配器改变接口以符合客户的期望 外观将客户从一个复杂的子系统中解耦 实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定 实现一个外观,需要将子系统组合进外观中,然后将工作委托给给子系统执行 适配器模式有两种形式:对象适配器和类适配器.类适配器需要用到多重继承 你可以为一个子系统实现一个以上的外观 适配器将一个对象包装起来以改变其接口;装饰着将一个对象包装起来以增加新的行为和责任;而外观将一群对象"包装"起来以简化其接口 项目地址 java设计模式实现 如果觉得有点收获,记得在项目上点star哦!

May 22, 2015 · 1 min · 28 words · Jimmy

设计模式之命令模式

命令模式 命令模式将发出请求的对象和执行请求的对象解耦 在被解耦的两者之间是通过命令对象进行沟通的.命令对象封装了接收者和一个或者一组动作 调用者通过调用命令封装execute()发出请求,这会使得接收者的动作被调用 调用者可以接受命令当做参数,甚至在运行时动态地进行 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态 宏命令是命令的一种简单的延伸,允许调用多个命令.宏方法也可以支持注销 实际操作时,很常见使用"聪明"命令对象,也就是直接实现了请求,而不是将工作委托给接收者 命令也可以用来实现日志和事务系统 项目地址 java设计模式实现 如果觉得有点收获,记得在项目上点star哦!

May 11, 2015 · 1 min · 12 words · Jimmy

设计模式之单例模式

有什么用处 有些对象其实我们只需要一个,比方说:线程池,缓存,对话框,注册表,日志对象…如果制造出多个实例,就会导致许多问题产生,例如程序的行为异常,资源使用过量,数据不一致 如何做 利用静态类变量,静态方法和适当的访问修饰符 定义 单例模式,确保一个类只有一个实例,并提供一个全局访问点 注意点,多线程中使用单例 如果有多个线程同时调用getInstance(),可能会产生多个实例,那就用synchronized(同步)关键字修饰 但是同步会降低性能,实际上也就第一次getInstance()时需要考虑同步问题,之后就没有同步问题. 1.如果getInstance()的性能对应用程序不是很关键,就加上synchronized关键字 /** * 单例模式之懒汉模式 * 优点:在需要实例的时候才进行第一次实例化,在资源紧缺的时候,可以减少不必要的资源消耗 * 缺点:同步了getInstance(),会造成性能浪费 */publicclassSingletonLazy { /** * 利用一个静态变量来记录Singleton类的唯一实例 */privatestatic SingletonLazy instance; /** * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 */privateSingletonLazy() { } /** * 用getInstance()实例化对象,并返回这个实例 * 在多线程中必须使用synchronized关键字修饰 * @return */publicstatic synchronized SingletonLazygetInstance() { //懒汉模式//如果未被实例化,则newif (instance ==null) { instance =new SingletonLazy(); } //如果已经实例化,则返回实例return instance; } } 2.如果getInstance()的性能对应用程序很关键,那就使用饿汉模式 使用饿汉模式 publicclassSingletonLazy{ //在静态初始化器(static initialize)中创建单例.这段代码保证了线程安全(Thread Safe)privatestatic SingletonLazy instance=new SingletonLazy(); privateSingletonLazy(){ } publicstatic SingletonLazygetInstance(){ //到这里,一定存在实例了,直接使用它return instance; } } 3.使用"双重检查锁"(double-checked locking),在getInstance()中减少使用同步 /** * 单例模式之使用"双重检查加锁" * 过程:在getInstance()中进行双重检查,确保一个实例 * 优点:在getInstance()中减少同步,增强性能,可以在多线程中使用 * 缺点:暂无 */publicclassSingletonDoubleCheckedLocking { /** * 利用一个静态变量来记录Singleton类的唯一实例 * volatile关键字确保:当instance变量被初始化为Singleton实例时,多个线程正确地处理instance变量 */privatestaticvolatile SingletonDoubleCheckedLocking instance; /** * 构造器声明为私有的,只有自己Singleton类才可以调用构造器 */privateSingletonDoubleCheckedLocking() { } /** * 用getInstance()实例化对象,并返回这个实例 * 方法不必用synchronized关键字修饰 * @return */publicstatic SingletonDoubleCheckedLockinggetInstance() { if(instance==null){//检查实例,如果不存在,则进入同步区块//注意:只有第一次调用getInstance()方法才彻底执行这里的代码 synchronized (SingletonDoubleCheckedLocking.class){ if(instance==null){//进入区块后,再检查一次,如果是null,才创建实例 instance=new SingletonDoubleCheckedLocking(); } } } return instance; } } 项目地址 java设计模式实现 如果觉得有点收获,记得在项目上点star哦!

May 10, 2015 · 1 min · 124 words · Jimmy