golang 控制语句 if, for, switch

golang 控制语句 if, for, switch http://www.cnblogs.com/howDo/archive/2013/06/01/GoLang-Control.html Go中的控制语句较精简,仅有 if, for, select 和 switch. 但使用时均比较灵活 if 在Go中条件语句 if 中如果条件部分的计算结果为 true 时将执行语句块,否则则执行else语句块(如果存在else时),此逻辑和其他语言中的if一样,但是在Go中还是有一些不同之处。 if 条件表达式不能使用括号 () 包含 if 语句代码片段必须使用 {}, 并且左括号必须和 if 在同一行 if 条件表达式的前面可以包含初始化语句, 支持平行赋值, 但不支持多个赋值语句 赋值 + 条件判断 if a, b := 21, 3; a > b { fmt.Println("a>b ? true") } 在if条件表达式前面声明的的变量只能在if-else语句块中使用。 if a, b := 21, 31; a > b { fmt.Println("a>b ? true") }else { fmt.Println(a,b) //Ok } fmt.Println(a,b) //error: undefined a ,undefined b 还需要注意的是如果在if-else 中包含return 时,编译器无法解析出else中的retrun,导致方法缺少return ,目前1.1版本已支持该方式。 ...

2013-07-09 · 3 min · 597 words · -

Cloc, 代码统计工具

Cloc, 代码统计工具 Cloc是一款使用Perl语言开发的开源代码统计工具,支持多平台使用、多语言识别,能够计算指定目标文件或文件夹中的文件数(files)、空白行数(blank)、注释行数(comment)和代码行数(code)。 pacman -S cloc cloc ~/projects/wiloon.com/ https://linux.cn/article-10118-1.html

2013-07-08 · 1 min · 9 words · -

LEAD TIME

LEAD TIME LEAD TIME是完成一项活动所需要的时间。这种活动通常指物料和产品的获得,无论是从外面购入的还是用自己的设备制造的。提前期可由下列各种时间或它们的总和组成: 订单准备时间、排队时间、加工时间、搬运时间或运输时间、接收和检测时间 前置时间 (Lead Time) ,也称前置期、备货周期 前置时间 (Lead time) 是供应链管理中的一个术语,是指从采购方开始下单订购到供应商交货所间隔的时间,通常以天数或小时计算。 减少前置时间可以使生产商和零售商平均库存水平得到减少,而且前置时间的减少可以使零售商订货模型更加稳定,也会给生产商的生产决策来带很大好处,能保证处于同一条供应链上的生产商和零售商实现双赢。 参考文献: http://wiki.mbalib.com/wiki/%E5%89%8D%E7%BD%AE%E6%97%B6%E9%97%B4

2013-07-02 · 1 min · 16 words · -

持续集成与测试自动化, CI, CD

持续集成与测试自动化, CI, CD CI, CD AND CD CI很容易理解,就是持续集成。但是CD既可以指代码持续交付,也可理解为代码持续部署。CI和CD之间有很多相似的部分,但是也有很大的区别。 持续集成 (CONTINUOUS INTEGRATION) 在持续集成环境中,开发人员将会频繁的提交代码到主干。这些新提交在最终合并到主线之前,都需要通过编译和自动化测试流进行验证。这样做是基于之前持续集成过程中很重视自动化测试验证结果,以保障所有的提交在合并主线之后的质量问题,对可能出现的一些问题进行预警。 持续交付 (CONTINUOUS DELIVERY) 持续交付就是讲我们的应用发布出去的过程。这个过程可以确保我们尽可能快的实现交付。这就意味着除了自动化测试,我们还需要有自动化的发布流,以及通过一个按键就可以随时随地实现应用的部署上线。 通过持续交付,您可以决定每天,每周,每两周发布一次,这完全可以根据自己的业务进行设置。 但是,如果您真的希望体验持续交付的优势,就需要先进行小批量发布,尽快部署到生产线,以便在出现问题时方便进行故障排除。 持续部署 (CONTINUOUS DEPLOYMENT) 如果我们想更加深入一步的话,就是持续部署了。通过这个方式,任何修改通过了所有已有的工作流就会直接和客户见面。没有人为干预 (没有一键部署按钮) ,只有当一个修改在工作流中构建失败才能阻止它部署到产品线。 持续部署是一个很优秀的方式,可以加速与客户的反馈循环,但是会给团队带来压力,因为不再有“发布日”了。开发人员可以专注于构建软件,他们看到他们的修改在他们完成工作后几分钟就上线了。基本上,当开发人员在主分支中合并一个提交时,这个分支将被构建、测试,如果一切顺利,则部署到生产环境中。 我从毕业到现在, 曾在大小不同的三个公司就职: 有民营的、有外资的、也有上市公司。 但以前大多都是做项目,从事软件开发工作,绝大部分公司对测试都不重视,即使有也没有成规模, 更谈不上建立测试体系。总之,重开发轻测试的管理思想在中国延续了几十年、并且还要继续,看看他们给测试工程师开的低工资和老师在课堂上讲到测试时一笔带过就知道测试被中国的老板所忽略。 最近两年,我从事CRM软件产品的测试、项目管理工作。 由于公司对软件的质量要求特别高, 这必然引起了大家对测试工作的重视,不但要求有强大的测试团队,该团队必须具备在业务方面、测试技能方面的专业水平, 而且在软件开发过程方面经常由于测试而作持续不断地调整。 幸运的是,随着软件开发技术和工具的提高,软件工程和软件过程实践的推广, 软件测试日益得到重视和专业化。 我从事测试工作期间,一直研究CMM、测试理论、自动化测试工具,并建立了一套完整的测试体系。 在此并不介绍整个测试体系,而是介绍测试方面最值得探讨的部分: 持续集成与测试自动化。目的是与大家共同进步。当然已经有很多关于持续集成和自动化测试方面的介绍,但我要介绍的不只是持续集成,也不只是自动化测试,而是测试如何的自动化. 二、测试自动化 自动化测试就是希望能够通过自动化测试工具或其他手段,按照测试工程师的预定计划进行自动的测试,目的是减轻手工测试的劳动量,从而达到提高软件质量的目的。自动化测试的目的在于发现老缺陷。而手工测试的目的在于发现新缺陷。 测试自动化涉及到测试流程、测试体系、自动化化编译、持续集成、自动发布测试系统以及自动化测试等方面整合。也就是说要让测试能够自动化,不仅是技术、工具的问题,更是一个公司和组织的文化问题。首先公司从资金、管理上支持您,其次要有专门的测试团队去建立适合自动化测试的测试流程、测试体系;其次就是把原代码从受控库中取出、编译、集成、发布可运行系统、进行自动化的单元测试和自动化的功能测试的过程。 (一) 、自动化测试的好处 对新版本执行回归测试--测试每个特征 对于产品型的软件,每发布一个新的版本,其中大部分功能和界面都和上一个版本相似或完全相同,这部分功能特别适合于自动化测试, 从而可以让测试达到测试每个特征的目的。 更多更频繁的测试--沉闷、耗时 我们的产品向市场的发布周期是3个月,也就是我们的开发周期只有短短的3个月,而在测试期间是每天/每2天都要发布一个版本供测试人员测试,一个系统的功能点有几千个上万个,人工测试是非常的耗时和繁琐,这样必然会使测试效率低下。 替代手工测试的困难--300个用户有些非功能性方面的测试: 压力测试、并发测试、大数据量测试、崩溃性测试,用人来测试是不可能达到的。 在没有引入自动化测试工具之前,为了测试并发,研发中心的一、两百号人在研发经理的口令: 1-、2-、3!, 大家同时按下同一个按钮。回想起这中情景也蛮有意思的。 具有一致性和可重复性 由于每次自动化测试运行的脚本是相同的, 所以每次执行的测试具有一致性, 人是很难做到的. 由于自动化测试的一致性,很容易发现被测软件的任何改变。 更好的利用资源--周未/晚上 理想的自动化测试能够按计划完全自动的运行, 在开发人员和测试人员不可能实行三班倒的情况下, 自动化测试可以胜任这个任务, 完全可以在周末和晚上执行测试. 这样充分的利用了公司的资源,也避免了开发和测试之间的等待. 解决测试与开发之间的矛盾 通常在开发的末期,进入集成测试阶段, 由于每发布一个版本的初期,测试系统的错误比较少,这时开发人员有等待测试人员测试出错误的时间. 事实上在叠代周期很短的开发模式中,存在更多的矛盾, 但自动化测试可以解决其中的主要矛盾。 ...

2013-06-30 · 1 min · 148 words · -

ADX指标

ADX指标 中文全称: 平均趋向指数 英文全称: Average Directional Index 或者Average Directional Movement Index 平均动向指标Average Directional Index, ADX 趋势分析指标的共同缺陷是适用于趋势市场状况,而不适用于震荡市场状况,ADX的发明旨在克服这一问题。ADX, Average Directional Index是由技术分析大师Welles Wilder发明的,他同时也是相对强弱指数RSI和抛物线止损反转指标Parabolic SAR的发明者。 国外投资者经常使用ADX指标,国内用的反而比较少,不过在编写交易系统时,经常用到ADX或者ATR指标判断盘整、振荡和单边趋势。 1.ADX指数是反映趋向变动的程度,而不是方向的本身。 2.进场与出场是采用+DI14与-DI14的穿越信号。 3.当极端点交易法则生效时,法则2将有例外。当DI发生穿越信号时,取当天的极端点做为止损点;换言之,多头头寸取当天的低价为止损点,空头头寸取当天的高价。在随后的几之内,如果止损点未被触及,即使DI再发生穿越信号也不需理会。 4.当ADX的位置高于两条DI而方向发生改变,这是趋势反转的早期信号,可以做部份的获利了结。最后的平仓信号是来自于DI穿越或极端点的止损被引发。当ADX改变方向时,如果+DI14高于-DI14,这代表趋势的变动是由上亦下,反之亦然。 5.如果ADX高于两条DI,而且读数明显偏高,这代表既有的趋势已经持续一段时间。这并不是建立新头寸的理想时机,因场信号很可能反复。换言之,ADX的读数偏高,相当于是超买/超卖,顺势的新交易头寸通常很难获利。 6.如果ADX同时低于两条DI,避免采用顺势交易的系统,因为市场中没有明显的趋势。 7.如果ADX的读数低于20~25,不论它与两条DI的相对位置如何,都避免采用顺势交易的系统,因为市场中没有明显的趋势 8.例: 在ADX为黄线,+DI为红线,-DI为绿线的前提下: 红线上行,绿线下行,且黄线与上行线同行,则价格上涨;如果绿线上行,红线下行,且黄线与上行线同行,则价格下跌。 9.通常情况下可以简单理解为: ADX线代表力量的强弱,+DI和-DI谁占优势随着力量一起上扬,那么就代表走势向哪个方向发展。 平均趋向指标ADX是另一种常用的趋势衡量指标。 ADX 无法告诉你趋势的发展方向。可是,如果趋势存在, ADX 可以衡量趋势的强度。不论上升趋势或下降趋势, ADX 看起来都一样。 ADX 的读数越大,趋势越明显。衡量趋 势强度时,需要比较几天的 ADX 读数,观察 ADX 究竟是上升或下降。 ADX 读数上升,代表趋势转强;如果 ADX 读数下降,意味着趋势转弱。当 ADx 曲线向上攀升,趋势越来越强,应该会持续发展。如果 ADX 曲线下滑,代表趋势开始转弱,反转的可能性增加。单就 ADX 本身来说,由于指标落后价格走势,所以算不上是很好的指标,不适合单就 ADX 进行操作。可是,如果与其他指标配合运用, ADX 可以确认市场是否存在趋势,并衡量趋势的强度。

2013-06-28 · 1 min · 62 words · -

number integer

number integer 建表的时候,如果是浮点数,一般设置为 number(m,n )[m为精度,n为小数位数,所以整数为m-n位], 整数设置为integer; 比如: create table abc ( a number(38,0), b number(38) c integer, d number ) 那么a,b,c,d 分别有什么区别呢? a,b其实是一样的,都是38位的范围; c是不是和a,b一样呢?测试后是不一样的,c的最大值可以达到9e125,显然远远地大于38位的范围; d和a,b,c有什么区别呢,首先d可以放小数,另外它的范围同样远远大于38位; 具体这a,b,c,d四种类型的明确差异,我也说不清楚,希望有专家把它解释清楚,我这里只是抛砖引玉。 以前我一直以为 integer=number(38,0) -38是number的最大精度 刚才无意中发现integer 是个超大的数据类型,最大可以表示为power(10,126)-1 也就是说这么大的数字,大概需要多少个字节呢, 因为一个字节最大表示256,那么N个字节最大表示power(256,n)>=power(10,126) 现在求这个N: 解法是: select LOG(256,10)*126 from dual 求得的解是 53, 也就是说,一个integer类型最少使用53个字节。 所以我觉得Integer类型还是尽量少用,一般很少用到这么大的数字; 特别是某些人对于boolean类型的处理; 因为Oracle的表结构中没有布尔类型,所以很多人干脆用integer 代替布尔类型,这个感觉有点"奢侈"; 我一般都用char(1) 表示布尔型;‘0’表示false,‘1’表示true 另外,比如varchar2(200)这个类型,它是动态分配的,所以字符串按实际使用的占用空间,但是integer却是固定暂用了最少53个字节,所以大部分时候,integer 类型还是不用为妙; 就算在pl/sql 里; 定义变量的时候,也不要使用integer; 可以用binary_integer 或pls_integer ;11g里还出了个新的整形,效率更高,叫simple_integer,反正最好不用integer就是了。 效率测试下来: simple_integer>pls_integer>binary_integer>integer; SIMPLE_INTEGER Subtype of PLS_INTEGER SIMPLE_INTEGER is a predefined subtype of the PLS_INTEGER data type that has the same range as PLS_INTEGER and has a NOT NULL constraint (explained in“NOT NULL Constraint”). It differs significantly from PLS_INTEGER in its overflow semantics. ...

2013-06-28 · 1 min · 138 words · -

关于数据驱动和关键字驱动的理解整理

关于数据驱动和关键字驱动的理解整理 关于数据驱动,以下这篇帖子还是给了很大的启发: http://bbs.51testing.com/viewthread.php?tid=113729&extra=&highlight=%CA%FD%BE%DD%C7%FD%B6%AF&page=1 摘录一些精妙的论点: 51testing论坛的phililschen: “什么是数据驱动呢?很大一部分人肯定认为数据驱动就是把需要参数化的东西写在EXCEL里,然后在跑脚本时调用。如果我告诉你,这其实不是数据驱动,而只是较高级的参数化,你肯定会很惊讶!现在我来解释一下: 首先为什么叫数据驱动呢,那么它肯定有驱动的含义,比如你用EXCEL可以控制测试的业务流吗?回答是不能的。那又如何作到驱动呢?所以说我们将测试数据放在独立的文件里只是高级的参数话。而数据驱动,你必须有数据来控制测试的业务流。比如你测一个WEB程序,有很多页面,你可以通过一个数据来控制每次是再哪个页面下工作的 (即通过数据来导航到相应的页面) 。它是关键字驱动的低级版本,他控制的是函数级的,而关键字是控制动作级的。所以数据驱动应该是可以控制整个测试的” 51testing论坛的dreamever: “数据驱动本身不是一个工业级标准的概念,因此在不同的公司,都会有好几个解释版本。首先我同意楼主的关于数据驱动的观点,也就是说如果我们仅仅是把测试数据放在数据文件里,这只是一种比较高级的参数化而已。其实我更倾向于把数据驱动理解为一种模式或者一种思想 对于数据驱动的讨论,我们不妨先抛开QTP来进行。无论是进行自动化测试还是手工测试时,我们都需要设计测试用例,准备测试数据,并且把测试用例与数据分开,在一套测试用例上运行多套测试数据是比较有效率的。我相信这一点大家应该都认同吧。 那么我们不妨再看一下手工测试的场景: 当一个手工测试人员A发现在测试数据存储目录下多了一套测试数据时,他就会意识到应该马上执行测试用例,并输入这套新的测试数据。其实是测试数据的变化触发了A的测试行为。 (有人可能说了我们公司不是这么做的,注意,我们不是在讨论实际的测试管理,我们在对测试模型进行抽象) 。如果我们更抽象一下,可以这样来看: 当测试数据变化时,测试用例就会被执行 (无论是A主动还是leader打电话通知) ,并且按照预先定义的规则去读取测试数据并执行测试用例。那么这种情况我们是不是可以理解为一种数据驱动呢?也就是说只要有了新的测试数据或者测试数据发生了变化,那么A就会去执行测试用例。这一过程的目的就是为了让所有的测试数据都得到输入并返回相应的输出结果。 如果大家同意上面的情景是一种数据驱动测试的例子,那么我们可以对自动化测试中的数据驱动进行同样的解释: 由机器自动读取测试数据,然后测试用具运行测试脚本执行测试用例,并按照预先设置好的参数化字段读取测试数据,返回测试结果。目的就是使所有的测试数据都得到输入,并返回输出,验证数据的输入和输出是否符合预期值。这里的测试数据不仅包括业务数据,还包括一些动作关键字或决策关键字,以提供足够的信息,让测试工具知道该调用什么样的脚本,应该如何处理各种情况。相对于不同的测试工具,其表现形式有可能不同,QTP提供了关键字视图和数据表,robot提出了决策表的概念,Watir的话本身没有什么特殊的模式,完全看测试人员把框架设计成什么样了。其实本质上都是消息驱动的不同表现而已,例如刚才的手工测试的例子,测试数据发生变化我们可以把它看成一种消息,接收到这个消息A就开始执行测试。” 51testing论坛的jackmail: “数据驱动中的 driven 一词,你可以简单的理解成导向,导向什么?结果。就是测试数据决定了测试结果,这就是所谓数据驱动,QTP实现了数据驱动的功能,模型,feature,特征,无非是个词汇而已,怎么说都没问题,用QTP你可以简单的完成你想实现的数据驱动方法的测试,他就是实现了xx功能。 还有关键字驱动,就是 关键字决定了结果。 在QTP里关键字就是step中的测试对象名称 (对象方法属性,或者值 (测试数据) ) 。测试对象名称的改变,就决定了结果的变更。以前有些人写的所谓框架是把对象从Excel表格中导入导出的,他们实现的就是关键字驱动。 什么驱动,就是什么决定结果。本来结果是固定的,由于驱动数据的变更,导致了结果的不同,没那么复杂。其实概念都是人定的,少去钻牛角尖,理解个大概意思就行了。” 最后引用一下一篇关键字驱动的理解的文章,毕竟这是QTP主推的东西 最初用QTP就是简单的录制,然后修改脚本,缺点如下: 应用软件必须具备一定的稳定性,并且在整个业务流程上都必须完整的实现了,否则顺序录制整能实现? 自动化脚本的维护性成本非常的高 自动化脚本的可重用性比较差 随之出现了关键字驱动的概念,一切都以对象为出发点,这有点像编程语言中从过程化向面向对象转化,在QTP中的具体实现方法是: 在单个程序界面上将测试所涉及到的对象手工添加到对象库中 在专家视图中基于对象库中的对象编写自动化测试脚本 以上这样做的明显的优点在于: 脚本的可控性非常的强,模块化组织也比较好 可以在开发完全实现所有的业务流程功能前就建立测试脚本,占据了比较大的主动性,为时间上的安排提供了更大的空间,一个词概括: “测试先行”

2013-06-27 · 1 min · 45 words · -

GC日志

GC日志 本文是 Plumbr 发行的 Java垃圾收集指南 的部分内容。文中将介绍GC日志的输出格式, 以及如何解读GC日志, 从中提取有用的信息。我们通过 -XX:+UseSerialGC 选项,指定JVM使用串行垃圾收集器, 并使用下面的启动参数让 JVM 打印出详细的GC日志: -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps 这样配置以后,发生GC时输出的日志就类似于下面这种格式(为了显示方便,已手工折行): 2015-05-26T14:45:37.987-0200: 151.126: [GC (Allocation Failure) 151.126: [DefNew: 629119K->69888K(629120K), 0.0584157 secs] 1619346K->1273247K(2027264K), 0.0585007 secs] [Times: user=0.06 sys=0.00, real=0.06 secs] 2015-05-26T14:45:59.690-0200: 172.829: [GC (Allocation Failure) 172.829: [DefNew: 629120K->629120K(629120K), 0.0000372 secs] 172.829: [Tenured: 1203359K->755802K(1398144K), 0.1855567 secs] 1832479K->755802K(2027264K), [Metaspace: 6741K->6741K(1056768K)], 0.1856954 secs] [Times: user=0.18 sys=0.00, real=0.18 secs] 上面的GC日志暴露了JVM中的一些信息。事实上,这个日志片段中发生了 2 次垃圾回收事件(Garbage Collection events)。其中一次清理的是年轻代(Young generation), 而第二次处理的是整个堆内存。下面我们来看,如何解读第一次GC事件,发生在年轻代中的小型GC(Minor GC): 2015-05-26T14:45:37.987-02001:151.1262:[GC3(Allocation Failure4) ...

2013-06-27 · 2 min · 283 words · -

subsonic 调用 存储过程

subsonic 调用 存储过程 [csharp] public static int GetRUID(string tblName) { StoredProcedure spd = new StoredProcedure(“GenerateRUID”); spd.Command.AddParameter("@tblName", tblName); spd.Command.AddOutputParameter("@currentnumber"); spd.Execute(); int currentnumber = int.Parse(spd.OutputValues[0].ToString()); return currentnumber; } [/csharp]

2013-06-27 · 1 min · 27 words · -

java 代码块

java 代码块 在编程过程中我们可能会遇到如下这种形式的程序: public class Test { { //... } } 这种形式的程序段我们将其称之为代码块,所谓代码块就是用大括号({})将多行代码封装在一起,形成一个独立的数据体,用于实现特定的算法。一般来说代码块是不能单独运行的,它必须要有运行主体。在Java中代码块主要分为四种: 一、 普通代码块 普通代码块是我们用得最多的也是最普遍的,它就是在方法名后面用{}括起来的代码片段。普通代码块是不能够单独存在的,它必须要紧跟在方法名后面。同时也必须要使用方法名调用它。 public class Test { public void test(){ System.out.println(“普通代码块”); } } 二、 静态代码块 想到静态我们就会想到static,静态代码块就是用static修饰的用{}括起来的代码片段,它的主要目的就是对静态属性进行初始化。 public class Test { static{ System.out.println(“静态代码块”); } } 三、 同步代码块 使用 synchronized 关键字修饰,并使用"{}"括起来的代码片段,它表示同一时间只能有一个线程进入到该方法块中,是一种多线程保护机制。 四、 构造代码块 在类中直接定义没有任何修饰符、前缀、后缀的代码块即为构造代码块。我们明白一个类必须至少有一个构造函数,构造函数在生成对象时被调用。构造代码块和构造函数一样同样是在生成一个对象时被调用,那么构造代码在什么时候被调用?如何调用的呢?看如下代码: 复制代码 public class Test { /** 构造代码 */ { System.out.println(“执行构造代码块…”); } /** * 无参构造函数 */ public Test(){ System.out.println("执行无参构造函数..."); } /** * 有参构造函数 * @param id id */ public Test(String id){ System.out.println("执行有参构造函数..."); } } ...

2013-06-27 · 2 min · 215 words · -

符号引用 直接引用

符号引用 直接引用 符号引用(Symbolic References), 直接引用 https://blog.csdn.net/u014296316/article/details/83066436 https://www.zhihu.com/question/30300585 http://blog.csdn.net/imzoer/article/details/8086255 JVM在装载class文件的时候,会有一步是将符号引用解析为直接引用的过程。 那么这里的直接引用到底是什么呢? 对于指向"类型"【Class对象】、类变量、类方法的直接引用可能是指向方法区的本地指针。 指向实例变量、实例方法的直接引用都是偏移量。实例变量的直接引用可能是从对象的映像开始算起到这个实例变量位置的偏移量。实例方法的直接引用可能是方法表的偏移量。 在《深入Java虚拟机》书的第197页我们可以看到,子类中方法表的偏移量和父类中的方法表的偏移量是一致的。比如说父类中有一个say()方法的偏移量是7,那么子类中say方法的偏移量也是7。 书中第199页说,通过"接口引用"来调用一个方法,jvm必须搜索对象的类的方法表才能找到一个合适的方法。这是因为实现同一个接口的这些类中,不一定所有的接口中的方法在类方法区中的偏移量都是一样的。他们有可能会不一样。这样的话可能就要搜索方法表才能确认要调用的方法在哪里。 而通过"类引用"来调用一个方法的时候,直接通过偏移量就可以找到要调用的方法的位置了。【因为子类中的方法的偏移量跟父类中的偏移量是一致的】 所以,通过接口引用调用方法会比类引用慢一些。 下面介绍下什么是接口引用。 interface A{void say();} class B implements A{} class C{public static void main(String []s){A a=new B();a.say()}} 在上面的第三行代码中,就是用"接口引用"来调用方法。 符号引用: 符号引用是一个字符串,它给出了被引用的内容的名字并且可能会包含一些其他关于这个被引用项的信息——这些信息必须足以唯一的识别一个类、字段、方法。这样,对于其他类的符号引用必须给出类的全名。对于其他类的字段,必须给出类名、字段名以及字段描述符。对于其他类的方法的引用必须给出类名、方法名以及方法的描述符。

2013-06-24 · 1 min · 35 words · -

gorm

gorm db.Table("go_service_info").Select("go_service_info.serviceId as service_id, go_service_info.serviceName as service_name, go_system_info.systemId as system_id, go_system_info.systemName as system_name").Joins("left join go_system_info on go_service_info.systemId = go_system_info.systemId").Scan(&results) db.Table("table0"). Select("table0.field0, table0.field1"). Joins("join table1 on table0.field0=table1.field0"). Where("table0.field0=? and table1.field1=?", foo, bar). First(&obj) https://gorm.io/zh_CN/docs/index.html https://cloud.tencent.com/developer/article/1674450

2013-06-20 · 1 min · 34 words · -

Linux 数据恢复工具

Linux 数据恢复工具 Safecopy、TestDisk、PhotoRec

2013-06-15 · 1 min · 3 words · -

mariaDB

mariaDB 个向后兼容、替代MySQL的数据库服务器。它包含所有主要的开源存储引擎。 为何改了个名字呢,这其中是有些典故的。 MySQL之父Widenius先生离开了Sun之后,觉得依靠Sun/Oracle来发展MySQL,实在很不靠谱,于是决定另开分支,这个分支的名字叫做MariaDB。 MariaDB跟MySQL在绝大多数方面是兼容的,对于开发者来说,几乎感觉不到任何不同。目前MariaDB是发展最快的MySQL分支版本,新版本发布速度已经超过了Oracle官方的MySQL版本。 在Oracle控制下的MySQL开发,有两个主要问题: 1. MySQL核心开发团队是封闭的,完全没有Oracle之外的成员参加。很多高手即使有心做贡献,也没办法做到。2. MySQL新版本的发布速度,在Oracle收购Sun之后大为减缓。Widenius有一个ppt,用数据比较了收购之前和之后新版本的发布速度。有很多bugfix和新的feature,都没有及时加入到发布版本之中。 以上这两个问题,导致了各个大公司,都开发了自己定制的MySQL版本,包括Yahoo!/Facebook/Google/阿里巴巴+淘宝网等等。 MySQL是开源社区的资产,任何个人/组织都无权据为己有。为了依靠广大MySQL社区的力量来更快速的发展MySQL,另外开分支是必须的。 MariaDB默认的存储引擎是Maria,不是MyISAM。Aria可以支持事务,但是默认情况下没有打开事务支持,因为事务支持对性能会有影响。可以通过以下语句,转换为支持事务的Aria引擎。ALTER TABLEtablenameENGINE=MARIATRANSACTIONAL=1; MariaDB源代码公开存放于Launchpad项目托管平台,同时也提供了二进制和编译包供下载。MariaDB基于事务的Maria存储引擎,替换了MySQL的MyISAM存储引擎,它使用了Percona的 XtraDB,InnoDB的变体,分支的开发者希望提供访问即将到来的MySQL 5.4 InnoDB性能。这个版本还包括了 PrimeBase XT (PBXT) 和 FederatedX存储引擎。

2013-06-14 · 1 min · 22 words · -

How browsers work

How browsers work http://taligarsiel.com/Projects/howbrowserswork1.htm http://ux.sohu.com/topics/50972d9ae7de3e752e0081ff

2013-06-10 · 1 min · 5 words · -

java 线程, 中断, isInterrupted()

java 线程, 中断, isInterrupted() Thread.interrupted() Java中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理中断。这好比是家里的父母叮嘱在外的子女要注意身体,但子女是否注意身体,怎么注意身体则完全取决于自己。 一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。而 Thread.interrupt 的作用其实也不是中断线程,而是 通知线程应该中断了,具体到底中断还是继续运行,应该由被通知的线程自己处理。具体来说,当对一个线程,调用 interrupt() 时, ① 如果线程处于被阻塞状态 (例如处于 sleep, wait, join 等状态) , 那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。仅此而已。 ② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。interrupt() 并不能真正的中断线程,需要被调用的线程自己进行配合才行。也就是说,一个线程如果有被中断的需求,那么就可以这样做。 ① 在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。 ② 在调用阻塞方法时正确处理InterruptedException异常。 (例如,catch异常后就结束线程。) Thread thread = new Thread(() -> { while (!Thread.interrupted()) { // do more work. } }); thread.start(); // 一段时间以后 thread.interrupt(); 具体到你的问题,Thread.interrupted()清除标志位是为了下次继续检测标志位。如果一个线程被设置中断标志后,选择结束线程那么自然不存在下次的问题,而如果一个线程被设置中断标识后,进行了一些处理后选择继续进行任务,而且这个任务也是需要被中断的,那么当然需要清除标志位了。 中断的原理 Java中断模型也是这么简单,每个线程对象里都有一个boolean类型的标识 (不一定就要是Thread类的字段,实际上也的确不是,这几个方法最终都是通过native方法来完成的) ,代表着是否有中断请求 (该请求可以来自所有线程,包括被中断的线程本身) 。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。 java.lang.Thread类提供了几个方法来操作这个中断状态,这些方法包括: public static boolean interrupted 测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false (在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外) 。 public boolean isInterrupted() 测试线程是否已经中断。线程的中断状态不受该方法的影响。 ...

2013-06-03 · 3 min · 456 words · -

Java JUC Atomic

Java JUC Atomic Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。原子变量的底层使用了处理器提供的原子指令,但是不同的CPU架构可能提供的原子指令不一样,也有可能需要某种形式的内部锁,所以该方法不能绝对保证线程不被阻塞。 在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。 基本类: AtomicInteger、AtomicLong、AtomicBoolean; 引用类型: AtomicReference、AtomicReference的ABA实例、AtomicStampedRerence、AtomicMarkableReference; 数组类型: AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 属性原子修改器 (Updater) : AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 看到这么多类,你是否觉得很困惑,其实没什么,因为你只需要看懂一个,其余的方法和使用都是大同小异的,相关的类会介绍他们之间的区别在哪里,在使用中需要注意的地方即可。 在使用Atomic系列前,我们需要先知道一个东西就是Unsafe类,全名为: sun.misc.Unsafe,这个类包含了大量的对C代码的操作,包括很多直接内存分配以及原子操作的调用,而它之所以标记为非安全的,是告诉你这个里面大量的方法调用都会存在安全隐患,需要小心使用,否则会导致严重的后果,例如在通过unsafe分配内存的时候,如果自己指定某些区域可能会导致一些类似C++一样的指针越界到其他进程的问题,不过它的具体使用并不是本文的重点,本文重点是Atomic系列的内容大多会基于unsafe类中的以下几个本地方法来操作: public final native boolean compareAndSwapObject(Object obj,long Fieldoffset, Object expect, Object update); public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2); 对象的引用进行对比后交换,交换成功返回true,交换失败返回false,这个交换过程完全是原子的,在CPU上计算完结果后,都会对比内存的结果是否还是原先的值,若不是,则认为不能替换,因为变量是volatile类型所以最终写入的数据会被其他线程看到,所以一个线程修改成功后,其他线程就发现自己修改失败了。 参数1: 被操作的对象 参数2: fieldoffset 被操作的域在对象中的偏移量,其实对比时是对比内存单元,所以需要属性的起始位置,而引用就是修改引用地址 (根据OS、VM位数和参数配置决定宽度一般是4-8个字节) ,int就是修改相关的4个字节,而long就是修改相关的8个字节。 获取偏移量也是通过unsafe的一个方法: objectFieldOffset(Fieldfield)来获取属性在对象中的偏移量;静态变量需要通过: staticFieldOffset(Field field)获取,调用的总方法是: fieldOffset(Fieldfield) 参数3: expect 域的期望值 参数4: update 域的更新值 对long的操作,要看VM是否支持对Long的CAS,因为有可能VM本身不支持,若不支持,此时运算会变成Lock方式,不过现在VM都基本是支持的而已。 public final native boolean compareAndSwapLong(Object paramObject, long paramLong1, long paramLong2, long paramLong3); ...

2013-06-03 · 6 min · 1152 words · -

排队自旋锁/Ticket Lock

排队自旋锁/Ticket Lock Ticket Lock 是为了解决自旋锁的公平性问题,类似于现实中银行柜台的排队叫号: 锁拥有一个服务号,表示正在服务的线程,还有一个排队号;每个线程尝试获取锁之前先拿一个排队号,然后不断轮询锁的当前服务号是否是自己的排队号,如果是,则表示自己拥有了锁,不是则继续轮询。 当线程释放锁时,将服务号加1,这样下一个线程看到这个变化,就退出自旋。 简单的实现 import java.util.concurrent.atomic.AtomicInteger; public class TicketLock { private AtomicInteger serviceNum = new AtomicInteger(); // 服务号 private AtomicInteger ticketNum = new AtomicInteger(); // 排队号 public int lock() { // 首先原子性地获得一个排队号 int myTicketNum = ticketNum.getAndIncrement(); // 只要当前服务号不是自己的就不断轮询 while (serviceNum.get() != myTicketNum) { } return myTicketNum; } public void unlock(int myTicket) { // 只有当前线程拥有者才能释放锁 int next = myTicket + 1; serviceNum.compareAndSet(myTicket, next); } } 缺点 ...

2013-06-03 · 1 min · 74 words · -

Strict-Workflow

Strict-Workflow A Chrome extension that helps you stay focused by blocking sites during work timers and letting you browse during break timers https://chrome.google.com/webstore/detail/cgmnfnmlficgeijcalkgnnkigkefkbhd

2013-06-02 · 1 min · 23 words · -

Spinlock(自旋锁), Ticket Spinlock, MCS Spinlock

Spinlock(自旋锁), Ticket Spinlock, MCS Spinlock 为什么要加锁 在 SMP 系统中,如果仅仅是需要串行地增加一个变量的值,那么使用原子操作的函数 (API) 就可以了。但现实中更多的场景并不会那么简单,比如需要将一个结构体A中的数据提取出来,然后格式化、解析,再添加到另一个结构体B中,这整个的过程都要求是「原子的」,也就是完成之前,不允许其他的代码来读/写这两个结构体中的任何一个。 这时,相对轻量级的原子操作API就无法满足这种应用场景的需求了, 我们需要一种更强的同步/互斥机制,那就是软件层面的「锁」的机制。 同步锁的「加锁」和「解锁」是放在一段代码的一前一后,成对出现的,这段代码被称为 Critical Section / Region (临界区) 。但锁保护的并不是这段代码本身,而是其中使用到的多核/多线程共享的变量,它「同步」(或者说串行化) 的是对这个变量的访问,通俗的语义就是“我有你就不能有,你有我就不会有”。 Linux中主要有两种同步锁,一种是 spinlock,一种是 mutex. spinlock 和 mutex 都既可以在用户进程中使用,也可以在内核中使用,它们的主要区别是: 前者不会导致睡眠和调度,属于 busy wait 形式的锁, 后者可能导致睡眠和调度,属于 sleep wait 形式的锁。 spinlock 是最基础的一种锁,像后面将要介绍的 rwlock(读写锁), seqlock(读写锁)等都是基于spinlock衍生出来的。就算是 mutex,它的实现与spinlock 也是密不可分。因此,本系列文章将首先围绕 spinlock展开介绍。 如何加锁 Linux 中 spinlock 机制发展到现在,其实现方式的大致有3种。 第一种实现 - 经典的 CAS 最古老的一种做法是: spinlock 用一个整形变量表示,其初始值为1,表示 available 的状态。当一个CPU (设为CPU A) 获得spinlock后,会将该变量的值设为0,之后其他CPU试图获取这个 spinlock 时,会一直等待,直到 CPU A 释放 spinlock, 并将该变量的值设为1。 那么其他的 CPU 是以何种形式等待的,如果有多个CPU一起等待,形成了竞争又该如何处理? 这里要用到经典的 CAS 操作 (Compare And Swap) 。 ...

2013-06-01 · 2 min · 330 words · -