Apache怎样设置主目录的路径

在apache目录的conf/httpd.conf文件中查找DocumentRoot,将DocumentRoot后面的路径修改为你想要的路径,应该有两处。 更改Apache的默认网站根目录地址方法如下: 1、找到 DocumentRoot “X:/Apache/htdocs” 将“X:/Apache/htdocs”改为你自定义的网站目录; 2、找到 <Directory “X:/Apache/htdocs”> 将“X:/Apache/htdocs”改为你自定义的网站目录; 3、完成。 注意:X代表实际的安装盘符目录。 需要重启apache服务 。

Json:json转化为List、Map案例

//json转换list public static List<?> jsonToList(String json, Class<?> elementClass) throws Exception { if (!Util.isBlank(json)) { if (!"[".equals(json.substring(0, 1))) { json = "[" + json + "]"; } ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); JavaType javaType = mapper.getTypeFactory() .constructParametricType(ArrayList.class, elementClass); return mapper.readValue(json, javaType); } return null; } // json转map public static Map<String, Object> parseJSON2Map(String jsonStr) throws Exception { List<Map<String, Object>> list = (List<Map<String, Object>>) jsonToList( jsonStr, Map.class); if (null != list && list.

42、关于在tomcat下部署workbench+kie-server 环境的步骤

第一步:下载环境 http://www.drools.org/download/download.html 下载地址。 将Kie Execution Server 解压之后会得到三个war包,我们只要其中一个即可: kie-server-6.4.0.Final-webc.war 将下载的 workbench的war 改成 kie-wb.war 将execution server的war改成 kie-server.war,并上传到tomcat/ webapps目录下。 配置与 之前讲的一样,只有两个地方是要做修改的。 第一: tomcat-users.xml 文件 <?xml version='1.0' encoding='utf-8'?> <tomcat-users> <role rolename="admin"/> <role rolename="kie-server"/> <!-- 这里要注意的一点是 Kie-server 的角色必须要写成 "kie-server" --> <user username="workbench" password="workbench1!" roles="admin,kie-server"/> <user username="kieserver" password="kieserver1!" roles="kie-server"/> <!-- kie-server 用户名及密码 要写成kieserver kieserver1! 否则 在规则部署中无法看到 官方说明,这是默认的用户名及密码 但还在实验中--> </tomcat-users> 解决上面默认密码的方案: 我们可以这样改写: <user username="helloword" password="helloword" roles="kie-server"/> 只要将setenv.sh中配置两条属性: org.kie.server.controller.user=helloword org.kie.server.controller.pwd=helloword 如果在setenv.sh 中并未设置上面两个属性,则必须要在tomcat.user.xml中设置默认的用户名密码。 否则就会报kieserver 401的一些没有权限的错误 如果我们在setenv.sh中设置了该属性,则在tomcat.user.xml就也可配置我们自定义的用户名密码了。 第二: setenv.sh 添加框中所画的值。这里要注意的是一点是kie.

springmvc中的bean的生成和使用顺序

如果bean中需要注入自动扫描目录中的备案,则必须在这面这句实现扫描功能语句之后 <!--自动扫描含有@Service将其注入为bean --> <context:component-scan base-package="cn.yxg.service" />

ASP.NET MVC中切换模板页(不同目录的cshtml文件)

看来以后建立一个父类控制器还是有必要的。。。 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace NETMVC切换模板.Controllers { public class BaseController : Controller { protected override void OnResultExecuting(ResultExecutingContext filterContext) { ViewResult viewResult = filterContext.Result as ViewResult; if (viewResult != null) { string x = Request.QueryString["x"]; string text = string.IsNullOrEmpty(x) ? "" : "/Templete/Blue"; string arg = string.IsNullOrEmpty(text) ? "" : text; string arg2 = filterContext.RequestContext.RouteData.Values["Controller"].ToString(); string arg3 = filterContext.RequestContext.RouteData.Values["Action"].ToString(); if (string.IsNullOrWhiteSpace(viewResult.ViewName)) { viewResult.ViewName = string.

C语言里的“宏”是指什么?

简单来说:宏定义又称为宏代换、宏替换,简称“宏”。是C提供的三种预处理功能的其中一种。 复杂的请看下面,讲的很全。下面的带参宏定义,多行宏定义,在Linux内核源码中很多。另外sizeof也是一个宏定义。 宏定义 宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译 1. 不带参数的宏定义: 宏定义又称为宏代换、宏替换,简称“宏”。 格式: #define 标识符 字符串 其中的标识符就是所谓的符号常量,也称为“宏名”。 预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。 掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。 即在对相关命令或语句的含义和功能作具体分析之前就要换: 例: #define PI 3.1415926 把程序中出现的PI全部换成3.1415926 说明: (1)宏名一般用大写 (2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义 (3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。 (4)宏定义末尾不加分号; (5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。 (6)可以用#undef命令终止宏定义的作用域 (7)宏定义可以嵌套 (8)字符串" "中永远不包含宏 (9)宏定义不分配内存,变量定义分配内存。 2. 带参数的宏定义: 除了一般的字符串替换,还要做参数代换 格式: #define 宏名(参数表) 字符串 例如:#define S(a,b) a*b area=S(3,2);第一步被换为area=a*b; ,第二步被换为area=3*2; 类似于函数调用,有一个哑实结合的过程: (1)实参如果是表达式容易出问题 #define S(r) r*r area=S(a+b);第一步换为area=r*r;,第二步被换为area=a+b*a+b; 正确的宏定义是#define S(r) ((r)*(r)) (2)宏名和参数的括号间不能有空格 (3)宏替换只作替换,不做计算,不做表达式求解 (4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存 (5)宏的哑实结合不存在类型,也没有类型转换。 (6)函数只有一个返回值,利用宏则可以设法得到多个值 (7)宏展开使源程序变长,函数调用不会 (8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值) 3. 宏定义其他冷门、重点知识 #define用法 1、 用无参宏定义一个简单的常量 #define LEN 12 这个是最常见的用法,但也会出错。 比如下面几个知识点你会吗?可以看下: (1) #define NAME "

支付流程简单逻辑分析

1.支付宝和银联的支付流程 常用的支付方式有: 1、支付宝支付 https://openhome.alipay.com/doc/docIndex.htm?url=https://openhome.alipay.com/doc/viewKbDoc.htm?key=236714&type=cat 支付流程: (1)先与支付宝签约,获取商户id(partner)和账号id(seller) (2)下载相应的公私钥文件(加密签名使用),在客户端我们可能只需要私钥 (3)下载支付宝sdk (4)生成订单信息,可以直接客户端或者自己服务端生存都可以,但是大多是服务端生存的。 (5)调用支付宝客户端,有支付宝客户端跟支付宝打交道 (6)支付完毕之后返回结果给客户端和服务端。 2、微信支付 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=1417694084&token=cd674b2fe840f8e60d09126cc5c7e2cd1317ffe6&lang=zh_CN 支付流程: (1)注册微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些参数详情见图 (2)下载微信支付sdk (3)客户端请求订单,后台与微信后台交互,返回给客户端支付参数; (4)调用微信客户端,由微信客户端和微信服务器打交道; (5)客户端和服务端都会收到支付结果;(前台消息不可靠,我们需要去后台验证,如果后台没有收到支付通知,后台去微信服务器验证然后将结果返回给客户端) 注意事项: 1)如果APP里面已经使用了ShareSDK,就有一些地方要注意。不要再重复导入微信的SDK,因为shareSDK里面的extend已经包括了微信的SDK。 2)微信本身是鼓励客户APP把签名算法放到服务器上面,这样信息就不容易被破解。但是如果客户APP本身没有服务器端,或者认为不需要放到服务器端,也可以直接把签名(加密)的部分直接放在APP端。Sample代码的注释有点乱,多次提到服务器云云,但是其实可以不这么做。 3、银联 支付流程: (1)注册申请就不是前端的事了,直接介入sdk (2)从自己的服务端获取流水号 (3)然后调用银联sdk,不用跳转,银联sdk直接是内嵌的 (4)支付完成之后会回调代理方法 4、内购 •请求有效的产品代号集合 •购买指定产品 •验证购买 •恢复购买 http://www.tairan.com/archives/2215/ 常用的支付方式有: 1、支付宝支付 https://openhome.alipay.com/doc/docIndex.htm?url=https://openhome.alipay.com/doc/viewKbDoc.htm?key=236714&type=cat 支付流程: (1)先与支付宝签约,获取商户id(partner)和账号id(seller) (2)下载相应的公私钥文件(加密签名使用),在客户端我们可能只需要私钥 (3)下载支付宝sdk (4)生成订单信息,可以直接客户端或者自己服务端生存都可以,但是大多是服务端生存的。 (5)调用支付宝客户端,有支付宝客户端跟支付宝打交道 (6)支付完毕之后返回结果给客户端和服务端。 2、微信支付 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=1417694084&token=cd674b2fe840f8e60d09126cc5c7e2cd1317ffe6&lang=zh_CN 支付流程: (1)注册微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些参数详情见图 (2)下载微信支付sdk (3)客户端请求订单,后台与微信后台交互,返回给客户端支付参数; (4)调用微信客户端,由微信客户端和微信服务器打交道; (5)客户端和服务端都会收到支付结果;(前台消息不可靠,我们需要去后台验证,如果后台没有收到支付通知,后台去微信服务器验证然后将结果返回给客户端) 注意事项: 1)如果APP里面已经使用了ShareSDK,就有一些地方要注意。不要再重复导入微信的SDK,因为shareSDK里面的extend已经包括了微信的SDK。 2)微信本身是鼓励客户APP把签名算法放到服务器上面,这样信息就不容易被破解。但是如果客户APP本身没有服务器端,或者认为不需要放到服务器端,也可以直接把签名(加密)的部分直接放在APP端。Sample代码的注释有点乱,多次提到服务器云云,但是其实可以不这么做。 3、银联 支付流程: (1)注册申请就不是前端的事了,直接介入sdk (2)从自己的服务端获取流水号 (3)然后调用银联sdk,不用跳转,银联sdk直接是内嵌的 (4)支付完成之后会回调代理方法 支付功能-需要返回哪些参数 公共返回参数 result_code返回码0为正常 result_msg返回信息,OK为正常 err_detail具体错误信息 id成功发起支付后返回支付表记录 不同的支付方式的返回参数有些不同,可以到官方文档去看。 支付宝返回参数说明

我为什么反对用各类框架

作者:find goo 链接:http://www.zhihu.com/question/36032573/answer/94592816 来源:知乎 著作权归作者所有,转载请联系作者获得授权。 我为什么反对用各类框架。 什么ssh,orm,spring,struct,复杂,速度慢,最后把自已框进去了。 如果有有一百万种框架学一百万年后,知道了那个最好,再开发? (这句话原本是,是如果人类几百年后有一百万种疫苗,你打一百万种疫苗来防病?这不是根本解决之道,根本解决之道是卫生锻炼) java占语言榜第一,全世界实际各个公司框架加在一起超过了一百万种。 答案是否定的,因为人的精力是有限的。 软件开发中复杂不会消失,用多种框架,复杂因会从代码跑到xml,更加复杂。 与其用各类多如牛毛的框架,多如牛毛的配置,不如用好jsp。 一,可视化是关键 为什么用jsp,当然是有原因的,一是ide支持,各个java ide都支持jsp,包括dreamwaver,好排版。你用各个标签ide不支持或支持有限,相当于用cgi拼文本来开发。 二、热更新 jsp和php类似支持热布置,各类标签,标注,模块,都是在走邪路,你要再开发一套支持它的ide或web排版工具,这不是捡了芝麻丢了西瓜。你再开发类似jsp的热更新,你又在重复造轮子。 三、jquery+ajax+json淘汰了mvc 没有ajax时,html标签和js,和jsp混在一起,但有了json,view层(html+jquery)通过json和c层(类似servlet,无html的jsp)通信,这样,在服务器实际mvc没有任何意义。 四、动态语言淘汰了spring 什么aop,ioc,各种概念无非是实际了动态化加载,关键用的xml丑陋无比。 其实软件需要动态性时我只要加入动态语言如groovy,beanshell,jtyhon,如beanshell(才200kb),你玩各种概念时,我已经用动态语言+代码生成器实现业务逻辑,早就好了,而且动态性没有我的高,我可以放入数据库中,web中做到真正的动态。 五、代码生成器淘汰了orm 第一次用orm时感觉很oop,但现在感觉orm是为了oop而oop,性能低下会导致你的网站没有可伸缩性,12306初期慢一部分归功于orm。不要忘了jdbc,其实这些orm代码我可以用代码生成器从jdbc生成orm,比各类orm性能高得多。 这样构建系统就不用ssh了。 显示层:jsp+jquery(json)+jsp.service=jsp做排版html+另一个jsp做排版json提供接口 jsp(只返回json)调用逻辑层。 逻辑层:groovy+java,必要时groovy的dsl也可以用上 数据访问层:代码生成器,生成类似orm,主要是灵活,性能最高,方便省事。 这样的快速开发,业务逻辑用groovy vs java+代码生成器的jdbc+jsp(也可用代码生成器生成部分),性能比ssh高得多,开发速度也快得多。 c,c++,python,c#,php,不用spring一样管理好程序,程序的框架说白了是一种管理代码能力,面向过程一样能管理好程序,java现在是过度oop的,过度设计模式,过度interface,过度xml,过度强调设计,过度依赖框架,很多优秀的开源工程,很少引用各种jar包,而各大做类erp的信息管理程序,一个程序本身可能只有几m,而jar包达到几百m,几个g,需要ibm的机器才能跑得动。 反思java,在web上,php就很好用,为什么?实际上jsp,完全可以胜过php,但因为引入了java的框架,导致jsp依赖下面的各种jar包,最后成了重量轻的框架,说实在的根本没必要引用各种多于牛毛的框架与jar包。因为引入任何框架和jar包会导致性能下降厉害,越是重量级的,越是下降得厉害,因为反射消耗性能。不要跟我说性能不重要,你写几个人用的程序,用asp就可以搞定,如果你写类似google全球人用的程序,每节省1%,服务器电费就节省1%。 反思java,是让java回归到简单模式,任何复杂,不会因为你用了什么语言会降低复杂性,复杂是守恒的,但语言的特征会带来复杂的乘数,如果java的框架把复杂乘数加到几倍,又是走入了c++的复杂泥谭,很多时候,我们只要写个代码生成器,根本不要什么ioc,aop,反射,这种影响性能的东西,用这些东西,我还不如直接加入jython,groovy,这种动态语言,如同c++加入lua一样。 c语言进入了依赖指针的泥潭(除数组传值你会死吗?) c++进入了模板的泥潭(能不能不要用模板装(a_c)?) c#进入了拖拉控件的泥潭(生成的html你看得下去吗?) java进入了过度框架的泥潭(不用框架就不能编程?) 我现在的c#代码生成器用的codesmith,crud整个框架的80%以上代码完全在ide中自动生成。 我用的java代码生成器是mygeneration,比codesmith慢一点,但也比eclipse的灵活得多,可直接生成js,html,crud程序75%以上代码可以自动生成。 我的c++,python代码生成器也是mygeneration,因为mygeneration是开源可以生成任意语言,codesmith和vs集成好但不开源。 说到分层,看到分一层的php,asp程序很好用,分二层的winform可以快速开发,分三层的java很多,mvc+三层开始复杂,html+jquery+json+mvc+三层开始头痛,最后发现有人用十二层,十五层做开发,中间分通信层,反sql注入层,报表层,安全检查层,插件层,业务流层,性能分析层,mock数据层,缓存处理层,负载均衡层等等,每层之间用spring强行隔离,报起错来大汗淋头,你这不是带着镣铐带着木枷跳舞吗?如果不是我骂他们,估计要分到十八层。下次干脆把开发人员放地狱拉倒。而且用你们这种框架分层开发出来的东西根本没办法复用,不符合软件工程的基本理论,软件主要讲究复用,用你这种框架出来后,能打个jar包到android下用吗?显然不能,因为依赖框架太多,很多框架在android下用不了或jar太大不好用。表面上追求复用无所不用其极,实际上你又进入了依赖分层,依赖框架的不可复用软件开发的陷阱上去了。 如果你要处罚一个程序员,让他用java的十八层框架开发,呵呵! java已经很慢,不要再用框架绑住了java的腿,不用把代码写进xml,不要使用存储过程,不要使用orm,不要使用spring,不要使用struts,不要使用servlet。 用jquery代替mvc,用json代替mvc,用jsp代替mvc,代替servlet,用groovy代替spring,用代码生成器代替orm。 jsp(做html显示,除session权限外没有任何java代码,和java没关系,方便美工可视化编辑)+jquery(ajax,获取json绑定)+jsp(调用业务逻辑java类,根据java业务逻辑生成json返回,没用任何html,类似restful接口)。 另外数据库表不要用自增id,用程序生成唯一标识符,现在硬盘都tb级别了,省几个字节解决不了问题,那一天数据访问量上去了,你的程序也不用改成id,分布性好,如果uuid太长,用base64转一下。 这个极其简单方案比ssh方便得多,性能高得多,可以分布式运行,伸缩性很好。 反思框架,反思框架,反思框架,重要的事说三遍。 c语言面向过程,一样管理几千万行的linux系统。 python面向过程,一样开发引力波程序。 c++面向过程和oop,一样可以开发搜索引擎。 不要把面向对象oop当做宝,面向对象主要是模拟人的思维,而人的思维和电脑是不一样的,所以面向对象性能低下,c++实际上通过编译把oop编译成了面向过程程序。其实很多时间用一个dsl动态程序或数据库操作就可以轻松搞定的,非要搞什么ioc,aop,反射,这种反人类的xml配置,结果Java成了web开发中复杂的代名词,和c++成了复杂语言一样,走偏了路。 用java开的android为什么比ios下的obj-c慢,原因很简单,过度包装过度设计,加上java虚拟机,影响性能,有了八核还会卡。有什么功能是ios实现不了,而android可以实现,几乎没有。android表面上设计先进,但实际是陷入了过度包装,过度设计的陷阱中。unix/ios/osx/linux/nginx ,这种简单设计的软件,性能稳定而直接。 面向对象(类,接口,泛型,等,复杂度设5)比面向过程复杂(函数,文件管理,算法,复杂度设3),如果加上框架(复杂度设10种),加上设计模式(复杂度23种),5*3*10*23=3450,复杂度超过了3450,再加上系统本身的复杂度(设为20),3450*20=69000,所以面向对象的复杂性,需要一个图书馆才能写下,所以类似c++这种可以用模板,用宏,用多重承继,用多级指针,用多种库的程序更加复杂,最后导致没人愿意用或只取一个子集,java的框架常见的有几十种,如果加上分层十来种,加上xml的复杂度,加上反射,加上工程化这些,程序的复杂度开始赶上c++了。所以很多老程序员宁愿用go语言,python语言,用php,用c语言,这种简单直观的程序,否则会掉进复杂程序的几万种排列组合的大坑中不能自拔,只会感觉软件越写越累,越写越烂,越写越慢,越写越不可维护,越写越需要学习更多。 大家都下过棋,普通人业余学学,五子棋几个子最简单,所以不需要学习,几分钟就入门了,象棋(明白几子规则即可)需要学习几天入门,而围棋(布局,定式,打劫,大龙对杀,妙手,收宫,流派要学的太多了,需要从几岁学起学几十年才有可能成为大师)因为复杂维数太大,需要学习几年,用电脑则需要google那种一天电费n万的深度学习系统才能玩得转,因为这种复杂性的增长到了后面会是指数增长,根本没办法控制。很多软件工程就是死在复杂性指数增长上,复杂度上去了,多一个乘数会把风险放大十倍以上,完不成任务是必定的,加班也是无法逃脱的。 过度设计,过度包装都不是好事,c++的模板类就是过度设计的结果,java中的各类框架也是过度设计结果。 我现在用面向对象用的是带类和接口的面向过程语言,尽量不用泛型,反射,动态加载,因为根本没必要,只要增加本项目的复杂度,如同用带模板的c++开发程序,如atl,这种东西很烦人,报起错误来一兜一兜的。 别为了技术而玩技术,如同c++一样,复杂被玩坏了,都没有人想学它了,java也是被这样技术狂热份子搞得越来越复杂,结果开发时间都浪费在这种复杂性学习和调试下,因为业务逻辑就很复杂,你再搞这个复杂乘数一乘,嘿嘿,自我折磨。 搞个xml配置就已为搞了个大新闻?实际上实现动态性的很多方法比这个水平高多了,比华来士的炸鸡更香。黑黑。 如果你跳出java接触了更多的软件或框架,很多程序根本不需要sping这种东西,如sap是用abap做为业务语言,是编译支持的,不需要Java这种复杂配置,virtualbox可以用python开发插件,很多游戏是用lua+c++实现动态性,firefox用的引擎加插件实现动态性,office是用的vba实现动态性,很多oa用提工作流实现动态性,最不管用的用友u8用的是多放几个备用字段实现动态性,最新的云计算公司用微服务实现动态性,还有一些商业开发平台用的是元数据实现动态性(和数据库原理一样),还用很多规则引擎,dsl,外挂,插件系统。。。总之静态语言实现动态性方法很多,或直接用python等动态语言,根本不需要用spring。 在只有sql数据库时代,人们总认为符合三范式的设计才是合格的设计,才是理所当然,等到移动互联网,大数据时代一来,三范式反而成了性能的裹脚布。软件开发,程序设计没有一层不变的真理,没有金科玉律,不要迷信前人的结论,有时需要反思,有时需要简化,需要以结果为导向,以效果为追求,才能取长补短。未来程序的框架和设计会越来越面向业务,而不是大一统的ssh这种缺乏弹性与伸缩性的n层的低性能框架。 ssh这种框架来源于sun的ejb的开源实现,ejb掉进了重量级的坑,sun以前一直靠卖提高这种重量级框架性能的服务器支撑着这个坑,据说有的做成cpu硬件指令,后来卖不掉了,不行了就卖给了oracle,前车之鉴,和c#的winform一样的,是两大奇葩,是oop过度设计的结果。主要原因是过度包装,过度设计影响服务器性能,框架复杂度乘数增长了软件工程成本,需要更多的人,天天在招人,天天在加班,需要更科层化的组织,更多签字的领导,很多程序弄来弄去只是内部的interface,程序内耗和沟通成本成指数增长。以至于一个操作系统内核面向过程语言可能十人就可以扛起80%代码,而一个类erp的oop框架系统可能需要上百个开发人员还不够,一个人加几个帮手可能开发出初始的android 系统,而几个团队可能开发一个android应用还吃力。可见简化管理能带来工作效率的提高,过度oop,复杂框架或设计是自找麻烦。 君不见一个facebook的phper可以和google比肩,三个程序员的独角兽公司可以秒国内n个程序员的类erp。他们肯定不是用ssh这种重量级框架。 面向过程开发者天天在旅游体验大道至简写好一个函数,面向对象开发者天天在梦游总想发明银弹实现万能框架。

硬件中断和软件中断的区别

中断 中断指当出现需要时,CPU暂时停止当前程序的执行转而执行处理新情况的程序和执行过程。即在程序运行过程中,系统出现了一个必须由CPU立即处理的情况,此时,CPU暂时中止程序的执行转而处理这个新的情况的过程就叫做中断。 硬件中断 硬件中断是一个异步信号, 表明需要注意, 或需要改变在执行一个同步事件. 硬件中断是由与系统相连的外设(比如网卡 硬盘 键盘等)自动产生的. 每个设备或设备集都有他自己的IRQ(中断请求), 基于IRQ, CPU可以将相应的请求分发到相应的硬件驱动上(注: 硬件驱动通常是内核中的一个子程序, 而不是一个独立的进程). 比如当网卡受到一个数据包的时候, 就会发出一个中断.处理中断的驱动是需要运行在CPU上的, 因此, 当中断产生时, CPU会暂时停止当前程序的程序转而执行中断请求. 一个中断只能中断一颗CPU(也有一种特殊情况, 就是在大型主机上是有硬件通道的, 它可以在没有主CPU的支持下, 同时处理多个中断).硬件中断可以直接中断CPU. 它会引起内核中相关代码被触发. 对于那些需要花费时间去处理的进程, 中断代码本身也可以被其他的硬件中断中断.对于时钟中断, 内核调度代码会将当前正在运行的代码挂起, 从而让其他代码来运行. 它的存在时为了让调度代码(或称为调度器)可以调度多任务. 软中断 软中断的处理类似于硬中断. 但是软中断仅仅由当前运行的进程产生.通常软中断是对一些I/O的请求.软中断仅与内核相联系, 而内核主要负责对需要运行的任何其他进程进行调度.软中断不会直接中断CPU, 也只有当前正在运行的代码(或进程)才会产生软中断. 软中断是一种需要内核为正在运行的进程去做一些事情(通常为I/O)的请求.有一个特殊的软中断是Yield调用, 它的作用是请求内核调度器去查看是否有一些其他的进程可以运行. 硬件中断和软中断的区别 硬件中断是由外设引发的, 软中断是执行中断指令产生的.硬件中断的中断号是由中断控制器提供的, 软中断的中断号由指令直接指出, 无需使用中断控制器.硬件中断是可屏蔽的, 软中断不可屏蔽.硬件中断处理程序要确保它能快速地完成任务, 这样程序执行时才不会等待较长时间, 称为上半部.软中断处理硬中断未完成的工作, 是一种推后执行的机制, 属于下半部.

Android qq 登录 界面 圆头像

1. 圆形头像及根据edittext输入对应值切换头像 1) 实现圆头像有很多方法,比如裁剪,遮罩,圆角等这些放发,我们利用实现圆角的方法来是实现圆头像如图2.1所示 图2.1 2) 通过新建一个Bitmap位图类型的带参数的构造方法,通过方法体新建了画布对图片进行了圆角的操作,然后对图片设置位图实现方法参数为图片位图的源,在方法体里通过图片获取高和宽度进行设置。如图2.2和2.3、2.4所示 图2.2 图2.3 图2.4 3) 我们对文本框里输入的用户名进行了对应的图片切换,通过对文本框里的文本改变设置了监听器,当文本框里的用变化时,获取文本框里的值,并对它进行转换值的类型,判断是否和对应的值匹配,如果匹配,图片源改变为对应的图片。如图2.5和2.6所示 图2.5 图2.6

直通BAT面试算法---智力题1-涂色练习题

1. 你要在一个nxm的格子图上涂色,你每次可以选择一个未涂色的格子涂上你开始选定的那种颜色。同时为了美观,我们要求你涂色的格子不能相邻,也就是说,不能有公共边,现在问你,在采取最优策略的情况下,你最多能涂多少个格子? 给定格子图的长n和宽m。请返回最多能涂的格子数目。 测试样例: 1,2 返回:1 class Paint { public: int getMost(int n, int m) { //右移一位即除以2 等同于 (n * m + 1) / 2 return (n * m + 1) >> 1; } }; #include<iostream> using namespace std; int getMost(int n, int m) { // write code here return (n*m+1)/2; } int main(){ int n,m,ans; cin >> n >> m; ans=getMost(n,m); cout << ans << endl; return 0; } 比如输入 3 5 输出 8

Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照

转载请注明出处: http://blog.csdn.net/lb377463323/article/details/52740411 Android API 21新增了Camera2,这与之前的camera架构完全不同,使用起来也比较复杂,但是功能变得很强大。 在讲解开启预览之前,首先需要了解camera2的几个比较重要的类: CameraManager: 管理手机上的所有摄像头设备,它的作用主要是获取摄像头列表和打开指定的摄像头CameraDevice: 具体的摄像头设备,它有一系列参数(预览尺寸、拍照尺寸等),可以通过CameraManager的getCameraCharacteristics()方法获取。它的作用主要是创建CameraCaptureSession和CaptureRequestCameraCaptureSession: 相机捕获会话,用于处理拍照和预览的工作(很重要)CaptureRequest: 捕获请求,定义输出缓冲区以及显示界面(TextureView或SurfaceView)等 1,定义TextureView作为预览界面 在布局文件中加入TextureView控件,然后实现其监听事件 textureView = (TextureView) findViewById(R.id.textureView); 然后我们可以在OnResume()方法中设置监听SurefaceTexture的事件 textureView.setSurfaceTextureListener(textureListener); 当SurefaceTexture准备好后会回调SurfaceTextureListener 的onSurfaceTextureAvailable()方法 TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { //当SurefaceTexture可用的时候,设置相机参数并打开相机 setupCamera(width, height); openCamera(); } }; 2,设置相机参数 为了更好地预览,我们根据TextureView的尺寸设置预览尺寸,Camera2中使用CameraManager来管理摄像头 private void setupCamera(int width, int height) { //获取摄像头的管理者CameraManager CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { //遍历所有摄像头 for (String cameraId: manager.getCameraIdList()) { CameraCharacteristics characteristics = manager.

条件变量的虚假唤醒(spurious wakeups)问题

引言 条件变量是我们常用的同步原语之一,它的正确使用方式一般如下图: 在wait端,我们必须把判断布尔条件和wait()放到while循环中,而不能用if语句,原因是可能会引起虚假唤醒。 那么,究竟什么是虚假唤醒,导致虚假唤醒的原因又是什么呢? 什么是虚假唤醒? 举个例子,我们现在有一个生产者-消费者队列和三个线程。 1) 1号线程从队列中获取了一个元素,此时队列变为空。 2) 2号线程也想从队列中获取一个元素,但此时队列为空,2号线程便只能进入阻塞(cond.wait()),等待队列非空。 3) 这时,3号线程将一个元素入队,并调用cond.notify()唤醒条件变量。 4) 处于等待状态的2号线程接收到3号线程的唤醒信号,便准备解除阻塞状态,执行接下来的任务(获取队列中的元素)。 5) 然而可能出现这样的情况:当2号线程准备获得队列的锁,去获取队列中的元素时,此时1号线程刚好执行完之前的元素操作,返回再去请求队列中的元素,1号线程便获得队列的锁,检查到队列非空,就获取到了3号线程刚刚入队的元素,然后释放队列锁。 6) 等到2号线程获得队列锁,判断发现队列仍为空,1号线程“偷走了”这个元素,所以对于2号线程而言,这次唤醒就是“虚假”的,它需要再次等待队列非空。 使用while()判断的原因 在多核处理器下,pthread_cond_signal可能会激活多于一个线程(阻塞在条件变量上的线程)。结果就是,当一个线程调用pthread_cond_signal()后,多个调用pthread_cond_wait()或pthread_cond_timedwait()的线程返回。这种效应就称为“虚假唤醒”。 Linux man page中也有提到: 虚假唤醒造成的后果: 需要对条件进行再判断以避免虚假唤醒: 如果用if判断,多个等待线程在满足if条件时都会被唤醒(虚假的),但实际上条件并不满足,生产者生产出来的消费品已经被第一个线程消费了。 这就是我们使用while去做判断而不是使用if的原因:因为等待在条件变量上的线程被唤醒有可能不是因为条件满足而是由于虚假唤醒。所以,我们需要对条件变量的状态进行不断检查直到其满足条件,不仅要在pthread_cond_wait前检查条件是否成立,在pthread_cond_wait之后也要检查。 参考资料: http://stackoverflow.com/questions/8594591/why-does-pthread-cond-wait-have-spurious-wakeups

解决GooglePlayStore提示您的设备与此版本不兼容(Your device isn't compatible with this version)

既然查到这个问题了,相信看这篇博客的人可能正在做一个比较复杂的企业级APP,想和国际接轨,但是在play store上却遇到了这个问题。这个问题出现在某些Android pad上。比如小米平板。下面我将带你解决这个看似麻烦,实际上很简单的问题。 首先,看一下出问题的截图,都是在play store上,都是国际大APP, 一个是统治印尼餐饮市场的Qraved 另一款是大名鼎鼎的Instagram 先说一下为什么会出现这个问题。在手机上是好用的,一到pad上就出现了问题。很容易想到,手机上有的功能,但是pad上没有,比如telephone。我们知道一些权限必须在manifest.xml中声明,所以问题就出现在这。 看一下,原来出问题的manifest.xml <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_UPDATES" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="com.imaginato.qravedconsumer.permission.MAPS_RECEIVE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="com.android.vending.CHECK_LICENSE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="

Android 自定义View实现城市选择列表

使用自定义View的方法,实现一个城市选择列表 手指滑动时 自定义View实现侧边栏,并提供回调接口 /** * Created by shixi_tianrui1 on 16-9-18. * 城市选择列表侧边栏 */ public class LetterSideBar extends View { // 字母列表 private List<String> mLetters = new ArrayList<>(); private OnTouchLetterListener mOnTouchLetterListener; private TextView mOverLayTextView; // 显示的字母 private int mWidth; private int mHeight; private int mEachLetterHeight; private int mEachLetterWidth; private Paint mPaint; private boolean maskShown; // 是否显示背景 private int mSelectedIndex = -1; // 已选择的字母 public LetterSideBar(Context context) { this(context, null); } public LetterSideBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LetterSideBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); // for test for (int i = 0; i < 26; i++) { char letter = (char) ('A' + i); Log.

Windows将安全性信息应用到以下对象时发生错误的解决

0x00前言 对于windows的用户权限、用户组权限等问题,windows 的文件/文件夹的所属权限控制一点也不逊色于linux/Uinx, 并且不是一般人所能可以轻松控制的。下面就来说说,我们在windows文件权限控制的一些问题。 0x01 所有者 1 右击文件夹【browsers】,这里我们可以选择右击某个文件或者某个文件夹或者整个磁盘。 2 【安全】-->>【高级】-->>【所有者】-->>【编辑】-->>【将所有者更改为】--【Adminitrators( LEVENO\Adiministrators)】--勾选【替换子容器和对象的所有者】-->>【应用】 0X02 权限 【安全】-->>【高级】-->>【权限】-->>【更改权限】-->>【添加权限】-->>【高级】-->>【立即查找】-->>【Adminitrator】-->>【确定】-->>【确定】-->>全选【允许】--【确定】-->>勾选【包括可从该对象的父项继承的权限】和【使用可从此对象继承的权限替换所有子对象权限】 0x03 确认权限 在完成上述步骤后,我们可以看到用户组的权限已经添加到文件夹的属性中去了。证明修改权限成功了。 欢迎大家分享更好的思路,热切期待^^_^^ !

双系统Ubuntu 引导修复(Boot Repair)

安装完双系统,如果在使用过程中不小心删除了Ubuntu引导向,则会导致开机后无法选择进入Ubuntu系统。或者当我们重装了windows系统后,也会发现原来的Ubuntu引导不见了,当出现这两种情况之一时,最好的解决办法不是重新把Ubuntu系统装一遍,我们只需要冲洗修复一下Ubuntu引导文件,就可以把问题解决了。 不过首先你需要Ubuntu U盘启动盘,来进入Ubuntu系统来修复引导问题。 第一步: 还是需要进入Ubuntu界面,但是并不需要安装(如果直接安装的话,以前在Ubuntu里面的文件可全部都没有了,所以万不得已,千 万别这样做)。 第二步: 选择TRY Ubuntu选项,进入U盘的Ubuntu 试用系统,并连接好网络(因为后续工作需要用到网络)。 第三步: 打开终端,终端快捷键是Ctrl+Alt+T,输入命令,添加boot-repair所在的源: sudo add-apt-repository ppa:yannubuntu/boot-repair && sudo apt-get update 第四步: 待上面命令执行完毕后,继续输入以下命令,安装boot-repair并且开启boot-repair: sudo apt-get install -y boot-repair && boot-repair 等一会,会出现如下的界面: 就会出现这个,点击Recommended repair,过几分钟重启就行了。 第五步: 如果上面已经执行成功了,可以跳过此部,否则,我们可以自己输入命令进行修复: sudo recommended repair 成功后,就会弹出我们的盘的各种信息以及引导的信息。 如果有些人不小心点击了Create a BootInfo summary的话,那你的开机启动界面将会出来一大堆你以前没见过的东西。 那样的话,你可以输入名令:cd /boot/grub 接着输入sudo gedit grub.cfg,打开grub.cfg文件后,通过搜索找到windows,然后把下面这些删去就和原来一样了。 BEGIN /etc/grub.d/25_custom menuentry “efi/EFI/Boot/bootx64.efi” { search –fs-uuid –no-floppy –set=root d000ed6a-5303-40aa-a517-af50e807c0e9 chainloader (${root})/efi/EFI/Boot/bootx64.efi } menuentry “efi/EFI/ubuntu/MokManager.efi” { search –fs-uuid –no-floppy –set=root d000ed6a-5303-40aa-a517-af50e807c0e9 chainloader (${root})/efi/EFI/ubuntu/MokManager.efi }

Win7 + Ubuntu16.04 双系统安装

之前安装win7 + Ubuntu14.04双系统,后来换成win10用了一段时间后觉得有些卡,而且装双系统装了几次都成功,所以又换回了win7系统,并重新安装了win7+Ubuntu16.04双系统,并把安装的过程汇总了一下,希望能对想安装双系统学习Linux系统的同学有所帮助! 整个安装过程主要分为以下几步: 一、 下载ubuntu16.04镜像; 二、 划分系统安装盘; 三、使用ultraISO制作Ubuntu 16.04系统U盘启动盘; 四、 安装Ubuntu系统; 五、 用EasyBCD 创建启动系统启动引导; (根据个人情况,选择性的安装) 一、 下载ubuntu16.04镜像 ubuntu系统官网免费下载地址 http://www.ubuntu.com/download/desktop 二、划分系统安装盘 右键点击我的电脑》管理》磁盘管理,选择一个空间较大的盘,右键选择压缩卷,笔者为Ubuntu16.04划分了80G的空间(空间大小根据自己的需要自行选择,建议如果只是安装作为练习使用有30G就可以,要是自己有运行的程序或者要处理数据还是建议多分一点空间),设置好容量大小后点压缩即可,不用给他设置盘符,我们在安装Ubuntu的时候在重新分区。注意:这种分区我们在Win7里面不能直接查看Ubuntu里的分区,但是在Ubuntu我们可以访问放在硬盘上的任何东西,也就是可以直接查看Win7系统的分区。 三、 使用ultraISO制作Ubuntu 16.04系统U盘启动盘; 百度下载ultraISO软件,强Ubuntu16.04系统写入安装U盘,作为系统安装启动盘 四、安装Ubuntu系统 在电脑上插入制作好的U盘启动盘,重启电脑,F2–》BIOS,选择boot界面,选择通过USB启动。(不同型号的电脑主板进入BIOS方式有区别) 注意:进入boot界面后,不要选择UEFI U盘启动,否则容易出现安装完成后系统无法引导重启进入ubuntu安装菜单,按下TAB键,输入live,按回车,就可进入安装界面在安装类型界然后选择最后一项“其他选项”,以为这样可以自己手动分区,点击继续。 现在我们看到的是硬盘的分区情况,找到前边有“空闲”二字,我们要做到就是,把空闲的空间给ubuntu划分分区。 点击“空闲”的分区,选择下边的“添加”,上边填写分区空间大小,下边填写要挂载的分区,然后确定。 /boot;引导分区,主分区,200M,起始,Ext4日志文件系统, 交换分区swap,逻辑分区,4000M,起始,交换空间,一般设置为同自己电脑内存大小即可; 根目录/,逻辑分区,15000M,起始,Ext4日志文件系统(10~15G即可); /home,逻辑分区,剩余空间数,起始,Ext4日志文件系统重要的一点是在安装启动引导设备选择前面划分的/boot盘,查看/boot分区的编号,然后在下边的“安装启动引导区的设备”下拉框中选择/boot分区的 安装完成后需要重新启动进入win7系统 四. 用EasyBCD 创建启动系统 下载并安装好EasyBCD step1:点击“添加新条目” step2:点击“linux/BSD” step3:类型GRUB(Legacy),名称ubuntu(自定义的),驱动器,这个就是当初/boot所在分区,就是200MB那个,在这里显示190MB,下面的分区4“Linux-190MB” step4:点击“添加条目” 现在你可以重启电脑,发现有Win7和Ubuntu两个启动下可以选择,选择Ubuntu启动项之后还可以自己选择进去Win7系统 五. 开启系统 做完这些重启系统后,系统会将win7系统和ubuntu 16.04系统都列出来,你可以选择系统进入了。 这样启动的好处(windows 不会受到Ubuntu的影响) 如果说没有最后这一步,没有任何问题,但是你要是启动windows7把Ubuntu系统的分区删除,那么就启动不了系统了

[JAVA]: springmvc常用注解标签详解

1、@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。 @Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式: (1)在SpringMVC 的配置文件中定义MyController 的bean 对象。 (2)在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。 <!--方式一--> <bean class="com.host.app.web.controller.MyController"/> <!--方式二--> < context:component-scan base-package = "com.host.app.web" />//路径写到controller的上一层(扫描包详解见下面浅析) 2、@RequestMapping RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。 RequestMapping注解有六个属性,下面我们把她分成三类进行说明(下面有相应示例)。 1、 value, method; value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明); method: 指定请求的method类型, GET、POST、PUT、DELETE等; 2、consumes,produces consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

天天写业务代码,如何成为技术大牛?

摘要: 写在前面 不管是开发、测试、运维,每个技术人员心理多多少少都有一个成为技术大牛的梦,毕竟“梦想总是要有的,万一实现了呢”!正是对技术梦的追求,促使我们不断地努力和提升自己。然而“梦想是美好的,现实却是残酷的”,很多同学在实际工作后就会发现,梦想是成为大牛,但做的事情看起来跟大牛都不沾边,例如,程序员说“天天写业务代码还加班,如何才能成为 写在前面 不管是开发、测试、运维,每个技术人员心理多多少少都有一个成为技术大牛的梦,毕竟“梦想总是要有的,万一实现了呢”!正是对技术梦的追求,促使我们不断地努力和提升自己。 然而“梦想是美好的,现实却是残酷的”,很多同学在实际工作后就会发现,梦想是成为大牛,但做的事情看起来跟大牛都不沾边,例如,程序员说“天天写业务代码还加班,如何才能成为技术大牛”,测试说“每天都有执行不完的测试用例”,运维说“扛机器接网线敲shell命令,这不是我想要的运维人生”。。。。。。知乎上类似的问题“天天写业务代码的程序员,怎么成为技术大牛,开始写技术代码?”关注人数有6K+,答案有120+,当时我也回答了并且点赞数最多,后来做职业等级晋升面评和沟通的时候,又有了新的发现和想法,于是有了系统的整理一篇文章的想法,希望让更多同学在技术大牛的路上能够少走一些弯路。 由于我是程序员,所以以下的一些例子都是基于程序开发的,但大道理是相通的,测试、运维都可以借鉴。 几个典型的误区 拜大牛为师 知乎上有人认为想成为技术大牛最简单直接、快速有效的方式是“拜团队技术大牛为师”,让他们平时给你开小灶,给你分配一些有难度的任务。 我个人是反对这种方法的,主要的原因有几个: 大牛很忙,不太可能单独给你开小灶,更不可能每天都给你开1个小时的小灶;而且一个团队里面,如果大牛平时经常给你开小灶,难免会引起其他团队成员的疑惑,我个人认为如果团队里的大牛如果真正有心的话,多给团队培训是最好的。然而做过培训的都知道,准备一场培训是很耗费时间的,课件和材料至少2个小时(还不能是碎片时间),讲解1个小时,大牛们一个月做一次培训已经是很高频了。因为第一个原因,所以一般要找大牛,都是带着问题去请教或者探讨。因为回答或者探讨问题无需太多的时间,更多的是靠经验和积累,这种情况下大牛们都是很乐意的,毕竟影响力是大牛的一个重要指标嘛。然而也要特别注意:如果经常问那些书本或者google能够很容易查到的知识,大牛们也会很不耐烦的,毕竟时间宝贵。经常有网友问我诸如“jvm的-Xmn参数如何配置”这类问题,我都是直接回答“请直接去google”,因为这样的问题实在是太多了,如果自己不去系统学习,每个都要问是非常浪费自己和别人的时间的。大牛不多,不太可能每个团队都有技术大牛,只能说团队里面会有比你水平高的人,即使他每天给你开小灶,最终你也只能提升到他的水平;而如果是跨团队的技术大牛,由于工作安排和分配的原因,直接请教和辅导的机会是比较少的,单凭参加几次大牛的培训,是不太可能就成为技术大牛的。 综合上述的几个原因,我认为对于大部分人来说,要想成为技术大牛,首先还是要明白“主要靠自己”这个道理,不要期望有个像武功师傅一样的大牛手把手一步一步的教你。适当的时候可以通过请教大牛或者和大牛探讨来提升自己,但大部分时间还是自己系统性、有针对性的提升。 业务代码一样很牛逼 知乎上有的回答认为写业务代码一样可以很牛逼,理由是业务代码一样可以有各种技巧,例如可以使用封装和抽象使得业务代码更具可扩展性,可以通过和产品多交流以便更好的理解和实现业务,日志记录好了问题定位效率可以提升10倍。。。。。。等等。 业务代码一样有技术含量,这点是肯定的,业务代码中的技术是每个程序员的基础,但只是掌握了这些技巧,并不能成为技术大牛,就像游戏中升级打怪一样,开始打小怪,经验值很高,越到后面经验值越少,打小怪已经不能提升经验值了,这个时候就需要打一些更高级的怪,刷一些有挑战的副本了,没看到哪个游戏只要一直打小怪就能升到顶级的。成为技术大牛的路也是类似的,你要不断的提升自己的水平,然后面临更大的挑战,通过应对这些挑战从而使自己水平更上一级,然后如此往复,最终达到技术大牛甚至业界大牛的境界,写业务代码只是这个打怪升级路上的一个挑战而已,而且我认为是比较初级的一个挑战。 所以我认为:业务代码都写不好的程序员肯定无法成为技术大牛,但只把业务代码写好的程序员也还不能成为技术大牛。 上班太忙没时间自己学习 很多人认为自己没有成为技术大牛并不是自己不聪明,也不是自己不努力,而是中国的这个环境下,技术人员加班都太多了,导致自己没有额外的时间进行学习。 这个理由有一定的客观性,毕竟和欧美相比,我们的加班确实要多一些,但这个因素只是一个需要克服的问题,并不是不可逾越的鸿沟,毕竟我们身边还是有那么多的大牛也是在中国这个环境成长起来的。 我认为有几个误区导致了这种看法的形成: 1)上班做的都是重复工作,要想提升必须自己额外去学习 形成这个误区的主要原因还是在于认为“写业务代码是没有技术含量的”,而我现在上班就是写业务代码,所以我在工作中不能提升。 2)学习需要大段的连续时间 很多人以为要学习就要像学校上课一样,给你一整天时间来上课才算学习,而我们平时加班又比较多,周末累的只想睡懒觉,或者只想去看看电影打打游戏来放松,所以就没有时间学习了。 实际上的做法正好相反:首先我们应该在工作中学习和提升,因为学以致用或者有实例参考,学习的效果是最好的;其次工作后学习不需要大段时间,而是要挤出时间,利用时间碎片来学习。我会在接下来的篇幅讲“如何在工作中学习提升”,至于如何利用时间碎片来学习,可以参考我的另外一篇文章《大牛养成指南(1):吃的草够多,你也能成为大牛》 正确的做法 Do more 做的更多,做的比你主管安排给你的任务更多。 我在HW的时候,负责一个版本的开发,这个版本的工作量大约是2000行左右,但是我除了做完这个功能,还将关联的功能全部掌握清楚了,代码(大约10000行)也全部看了一遍,做完这个版本后,我对这个版本相关的整套业务全部很熟悉了。经过一两次会议后,大家发现我对这块掌握最熟了,接下来就有趣了:产品讨论需求找我、测试有问题也找我、老大对外支撑也找我;后来,不是我负责的功能他们也找我,即使我当时不知道,我也会看代码或者找文档帮他们回答。。。。。。最后我就成了我这个系统的“专家”了。虽然这个时候我还是做业务的,还是写业务代码,但是我已经对整个业务都很熟悉了。 以上只是一个简单的例子,其实就是想说:要想有机会,首先你得从人群中冒出来,要想冒出来,你就必须做到与众不同,要做到与众不同,你就要做得更多! 怎么做得更多呢?可以从以下几个方面着手: 1)熟悉更多业务,不管是不是你负责的;熟悉更多代码,不管是不是你写的 这样做有很多好处,举几个简单的例子: 需求分析的时候更加准确,能够在需求阶段就识别风险、影响、难点问题处理的时候更加快速,因为相关的业务和代码都熟悉,能够快速的判断问题可能的原因并进行排查处理方案设计的时候考虑更加周全,由于有对全局业务的理解,能够设计出更好的方案 2)熟悉端到端 比如说你负责web后台开发,但实际上用户发起一个http请求,要经过很多中间步骤才到你的服务器(例如浏览器缓存、DNS、nginx等),服务器一般又会经过很多处理才到你写的那部分代码(路由、权限等)这整个流程中的很多系统或者步骤,绝大部分人是不可能去参与写代码的,但掌握了这些知识对你的综合水平有很大作用,例如方案设计、线上故障处理这些更加有含金量的技术工作都需要综合技术水平。 “系统性”、“全局性”、“综合性”这些字眼看起来比较虚,但其实都是技术大牛的必备的素质,要达到这样的境界,必须去熟悉更多系统、业务、代码。 3)自学 一般在比较成熟的团队,由于框架或者组件已经进行了大量的封装,写业务代码所用到的技术确实也比较少,但我们要明白“唯一不变的只有变化”,框架有可能要改进,组件可能要替换,或者你换了一家公司,新公司既没有组件也没有框架,要你从头开始来做。这些都是机会,也是挑战,而机会和挑战只会分配给有准备的人,所以这种情况下我们更加需要自学更多东西,因为真正等到要用的时候再来学已经没有时间了。 以java为例,大部分业务代码就是if-else加个数据库操作,但我们完全可以自己学些更多java的知识,例如垃圾回收,调优,网络编程等,这些可能暂时没用,但真要用的时候,不是google一下就可以了,这个时候谁已经掌握了相关知识和技能,机会就是谁的。 以垃圾回收为例,我自己平时就抽时间学习了这些知识,学了1年都没用上,但后来用上了几次,每次都解决了卡死的大问题,而有的同学,写了几年的java代码,对于stop-the-world是什么概念都不知道,更不用说去优化了。 Do better 要知道这个世界上没有完美的东西,你负责的系统和业务,总有不合理和可以改进的地方,这些“不合理”和“可改进”的地方,都是更高级别的怪物,打完后能够增加更多的经验值。识别出这些地方,并且给出解决方案,然后向主管提出,一次不行两次,多提几次,只要有一次落地了,这就是你的机会。 例如: 重复代码太多,是否可以引入设计模式? 系统性能一般,可否进行优化? 目前是单机,如果做成双机是否更好? 版本开发质量不高,是否引入高效的单元测试和集成测试方案? 目前的系统太庞大,是否可以通过重构和解耦改为3个系统? 阿里中间件有一些系统感觉我们也可以用,是否可以引入 ? 。。。。。。。。。。。。。。。。。。。 只要你去想,其实总能发现可以改进的地方的;如果你觉得系统哪里都没有改进的地方,那就说明你的水平还不够,可以多学习相关技术,多看看业界其它公司怎么做,BAT都怎么做。 我2013年调配到九游,刚开始接手了一个简单的后台系统,每天就是配合前台做数据增删改查,看起来完全没意思,是吧?如果只做这些确实没意思,但我们接手后做了很多事情: 解耦,将一个后台拆分为2个后台,提升可扩展性和稳定性;双机,将单机改为双机系统,提高可靠性;优化,将原来一个耗时5小时的接口优化为耗时5分钟 还有其它很多优化,后来我们这个组承担了更多的系统,后来这个小组5个人,负责了6个系统。 Do exercise 在做职业等级沟通的时候,发现有很多同学确实也在尝试Do more、Do better,但在执行的过程中,几乎每个人都遇到同一个问题:光看不用效果很差,怎么办? 例如: 学习了jvm的垃圾回收,但是线上比较少出现FGC导致的卡顿问题,就算出现了,恢复业务也是第一位的,不太可能线上出现问题然后让每个同学都去练一下手,那怎么去实践这些jvm的知识和技能呢?Netty我也看了,也了解了Reactor的原理,但是我不可能参与Netty开发,怎么去让自己真正掌握Reactor异步模式呢?看了《高性能MySQL》,但是线上的数据库都是DBA管理的,测试环境的数据库感觉又是随便配置的,我怎么去验证这些技术呢?框架封装了DAL层,数据库的访问我们都不需要操心,我们怎么去了解分库分表实现? 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 诸如此类问题还有很多,我这里分享一下个人的经验,其实就是3个词:learning、trying、teaching! 1)Learning

TMS320C6678外部存储器SPI FLASH硬件设计以及软件调试

文章主要介绍了一下,TMS320C6678 DSP的SPI FLASH的硬件设计需要注意的问题以及相应的软件调试的问题。 ------作者:jiangwenj02【转载请注明】 一、SPI FLASH 硬件设计 TMS320C6678 SPI模块拥有SPISCS0、SPISCS1、SPICLK、SPIDIN、SPIDOUT5个管脚,其中SPISCS0、SPISCS1为片选管脚,SPICLK为SPI提供时钟,SPIDIN是数据接受管脚,SPIDOUT为数据传送管脚。选用芯片N25Q128A11ESF40G,将管脚连接好就可以。参考官方设计板就可以。 二、SPI FLASH 软件调试 多核DSP为了简化BOOT流程,在内部集成了一段ROM,大小为128KB,存储RBL指令代码。RBL将外部主机或者flash存储器中的程序搬移到内存之中。我们选择用SPI挂载16MB的NOR Flash。该flash大小合适,接线简单。将配置DSP BOOT方式的管脚GPIO[0..15]连接到FPGA。这样在DSP正常启动之后,GPIO还可以作为DSP和FPGA的通信桥梁。 BOOT采用SPI FLASH,其中DSP BOOTMODE[2:0]选择boot器件,选择SPI,即DSP BOOTMODE[2:0]=6;N25Q128 FLASH 为24为地址的flash,因此DSP_BOOTMODE[9] = 1。 在调试FLASH存储器是否能正常工作的情况下,不将DSP设置在boot工作方式下。 调试程序选择K1_STK_v1.1提供的开源代码,K1_STK_v1.1中对SPI的测试代码为SPI工程。只测试SPI FLASH将前边的测试选项改成如下: #define SPI_LOOPBACK_TEST 0 #define SPI_NOR_FLASH_TEST 1 #define SPI_EDMA_TEST 0 注意:在最开始调试SPI FLASH的时候,我也是一直调不通,根本没有办法从FLASH中读取数据。一直到不到原因,重新购买的芯片也不行。后来直接换了一款芯片 N25Q128A11ESF40G,以前用的是官方板上的芯片,然后就好用了。个人认为原因是N25Q128A21BSF40F这款芯片已经停产了,市面上的都有问题。所以一定要选没停产的芯片,价格还便宜。 程序下载地址:http://download.csdn.net/detail/a137376864/9795887

apache更改主站目录

在php开发过程中,安装的apache的默认目录是在/var/www/,这个目录下有时会有用户权限,比如使用php上传文件到项目目录下时会有权限,这样就不能对所上传的文件进行修改,此时可以通过修改apache2的网站默认目录,这样就避免了上述出现的问题。 更改过程比较简单,只需要对apache2的配置文件进行修改就可以了 sudo gedit /etc/apache2/sites-enabled/000-default 在文档中找到DocumentRoot这个字段,在后面修改你要放置网页文件的目录,然后保存,然后重启apache服务: sudo service apache2 restart 这样网站默认目录就被修改了。 连接phpmyadmin 在安装过程中用户可能会把phpmyadmin也配置上了,此时可以直接将phpmyadmin整个文件夹移动到你修改的网站默认目录下面就可以了。这样就可以访问phpmyadmin了。 如果设置成主目录是/home/web/,默认这个目录是没有权限访问的,会提示 You don't have permission to access /index.php on this server. 打开//etc/apache2/apache2.conf,添加 <Directory /home/web/> Options Indexes FollowSymLinks AllowOverride None Allow from all </Directory> 注意,修改根目录的访问权限 <Directory /> Options FollowSymLinks AllowOverride None Order deny,allow Allow from all </Directory> sudo service apache2 restart

如何创建只读权限oracle账户

1.创建角色 CREATE ROLE SELECT_ROLE 2.给角色分配权限 grant SELECT ANY DICTIONARY to SELECT_ROLE; grant SELECT ANY TABLE to SELECT_ROLE; grant SELECT ANY TRANSACTION to SELECT_ROLE; grant SELECT ANY SEQUENCE to SELECT_ROLE; 3.把角色赋予指定账户 grant SELECT_ROLE to user; 4.删除角色 drop role SELECT_ROLE; 5.检查角色的权限 select * from dba_sys_privs where grantee=’SELECT_ROLE’ 测试权限的时候需要加上用户的对象例如 select count(*) from hr.ex_user;

【转载】C++ 宏定义

一、#define的基本用法 #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时,把运行结果理解错误,这对 C语言的学习很不利。 1 #define命令剖析 1.1 #define的概念 #define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。 该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义。 (1)简单的宏定义: #define <宏名> <字符串> 例: #define PI 3.1415926 (2) 带参数的宏定义 #define <宏名>(<参数列表>) <宏体> 例: #define A(x) x 一个标识符被宏定义后,该标识符便是一个宏名。这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换,替换后才进行编译,宏替换是简单的替换。 1.2 宏替换发生的时机 为了能够真正理解#define的作用,让我们来了解一下对C语言源程序的处理过程。当我们在一个集成的开发环境如Turbo C中将编写好的源程序进行编译时,实际经过了预处理、编译、汇编和连接几个过程。其中预处理器产生编译器的输出,它实现以下的功能: (1)文件包含 可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。 (2)条件编译 预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。 (3)宏展开 预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能,由预处理器来完成。 经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。 2 #define使用中的常见问题解析 2.1 简单宏定义使用中出现的问题 在简单宏定义的使用中,当替换文本所表示的字符串为一个表达式时,容易引起误解和误用。如下例: #define N 2+2 void main() { int a=N*N; printf(“%d”,a); } (1) 出现问题: 在此程序中存在着宏定义命令,宏N代表的字符串是2+2,在程序中有对宏N的使用,一般同学在读该程序时,容易产生的问题是先求解N为2+2=4,然后在程序中计算a时使用乘法,即N*N=4*4=16,其实该题的结果为8,为什么结果有这么大的偏差? (2) 问题解析: 如1节所述,宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方 只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2+2*2+2,计算后=8,这就是宏替换的实质,如何写程序才能完成结果为16的运算呢? (3)解决办法: 将宏定义写成如下形式 #define N (2+2) 这样就可替换成(2+2)*(2+2)=16

Java 去除数组空元素

private String[] removeArrayEmptyTextBackNewArray(String[] strArray) { List<String> strList= Arrays.asList(strArray); List<String> strListNew=new ArrayList<>(); for (int i = 0; i <strList.size(); i++) { if (strList.get(i)!=null&&!strList.get(i).equals("")){ strListNew.add(strList.get(i)); } } String[] strNewArray = strListNew.toArray(new String[strListNew.size()]); return strNewArray; }

获取apk签名 获取apk签名的hash值

public void getSignature() { PackageManager manager = getPackageManager(); StringBuilder builder = new StringBuilder(); String pkgname = getPackageName(); boolean isEmpty = pkgname.isEmpty(); if (isEmpty) { Toast.makeText(this, "应用程序的包名不能为空!", Toast.LENGTH_SHORT); } else { try { PackageInfo packageInfo = manager.getPackageInfo(pkgname, PackageManager.GET_SIGNATURES); Signature[] signatures = packageInfo.signatures; Signature sign = signatures[0]; byte[] signByte = sign.toByteArray(); Log.e("getSingInfo", bytesToHexString(signByte)); Log.e("getSingInfo hash", bytesToHexString(generateSHA1(signByte))); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } } } public static byte[] generateSHA1(byte[] data) { try { // 使用getInstance("

WEUI应用,用JS封装常用信息提示的弹层—Dialog

WEUI应用,用JS封装常用信息提示的弹层—Dialog 这样可以方便调用,而且文字可以自定义; <!DOCTYPE html> <html lang="zh-cmn-Hans"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0"> <title>WeUI</title> <link rel="stylesheet" href="style/weui.min.css"/> <link rel="stylesheet" href="example/example.css"/> <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script> <script> $(function(){ $('#showDialog_1').click(function(){ dialog('这是标题','这里是内容',function(){ alert("这里放你想做的相应操作!"); $('#dialog1').remove(); }); }); $('#showDialog_2').click(function(){ dialog('第二种标题','第二种内容'); }); function dialog(title, msg, callback){ var dialog1, dialog2; dialog1 = '\ <div class="weui_dialog_confirm" id="dialog1" style="display: none;">\ <div class="weui_mask"></div>\ <div class="weui_dialog">\ <div class="weui_dialog_hd"><strong class="weui_dialog_title">' + title + '</strong></div>\ <div class="weui_dialog_bd">' + msg + '</div>\ <div class="weui_dialog_ft">\ <a href="javascript:;" class="weui_btn_dialog default"

WEUI应用,用JS封装常用信息提示的弹层—Toast

***WEUI应用,用JS封装常用信息提示的弹层—Toast 这样可以方便调用,而且文字可以自定义;* <!DOCTYPE html> <html lang="zh-cmn-Hans"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0"> <title>WeUI</title> <link rel="stylesheet" href="style/weui.min.css"/> <link rel="stylesheet" href="example/example.css"/> <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script> <script> $(document).on("click","#showToast",function(){ //toast(); toast("我的自定义"); }); $(document).on("click","#showLoadingToast",function(){ //loadingToast(); loadingToast('自定义文字'); setTimeout(function(){ $('#loadingToast').fadeOut('fast'); },1800); }); function toast(){ var msg; arguments[0] ? msg = arguments[0] : msg = '已完成'; var toast; toast = '\ <div id="toast" style="display:none;">\ <div class="weui_mask_transparent"></div>\ <div class="weui_toast">\ <i class="weui_icon_toast"></i>\ <p class="weui_toast_content">' + msg + '</p>\ </div>\ </div>\ '; if(!

马尔可夫随机场(Markov Random Field)与马尔可夫链

1.什么是随机过程? 在当代科学与社会的广阔天地里,人们都可以看到一种叫作随机过程的数学模型:从银河亮度的起伏到星系空间的物质分布、从分子的布朗运动到原子的蜕变过程,从化学反应动力学到电话通讯理论、从谣言的传播到传染病的流行、从市场预测到密码破译,随机过程理论及其应用几乎无所不在。人类历史上第一个从理论上提出并加以研究的过程模型是马尔科夫链,它是马尔科夫对概率论乃至人类思想发展作出的又一伟大贡献。 2.什么是马尔科夫随机过程和马尔科夫链 马尔科夫过程,是指下一个时间点的指只与当前值有关系,与以前没有关系,即未来决定于现在而不是过去。 用一个通俗的比喻来形容,一只被切除了大脑的白鼠在若干个洞穴间的蹿动就构成一个马尔科夫链。因为这只白鼠已没有了记忆,瞬间而生的念头决定了它从一个洞穴蹿到另一个洞穴;当其所在位置确定时,它下一步蹿往何处与它以往经过的路径无关。这一模型的哲学意义是十分明显的,用前苏联数学家辛钦(1894-1959〕的话来说,就是承认客观世界中有这样一种现象,其未来由现在决定的程度,使得我们关于过去的知识丝毫不影响这种决定性。这种在已知 “现在”的条件下,“未来”与“过去”彼此独立的特性就被称为马尔科夫性,具有这种性质的随机过程就叫做马尔科夫过程,其最原始的模型就是马尔科夫链。 换个说法:马尔科夫随机过程是一类随机过程 马尔科夫随机过程是一类随机过程。它的原始模型马尔可夫链,由俄国数学家A.A.马尔可夫于1907年提出。该过程具有如下特性:在已知目前状态 (现在)的条件下,它未来的演变 (将来)不依赖于它以往的演变 ( 过去 ) 。 例如森林中动物头数的变化构成——马尔可夫过程。在现实世界中,有很多过程都是马尔可夫过程,如液体中微粒所作的布朗运动、传染病受感染的人数、车站的候车人数等,都可视为马尔可夫过程。关于该过程的研究,1931年A.H.柯尔莫哥洛夫在《概率论的解析方法》一文中首先将微分方程等分析的方法用于这类过程,奠定了马尔可夫过程的理论基础。1951年前后,伊藤清建立的随机微分方程的理论,为马尔可夫过程的研究开辟了新的道路。1954年前后,W.费勒将半群方法引入马尔可夫过程的研究。流形上的马尔可夫过程、马尔可夫向量场等都是正待深入研究的领域。 人们在实际中常遇到具有下述特性的随机过程:在已知它目前的状态(现在)的条件下,它未来的演变(将来)不依赖于它以往的演变(过去)。这种已知“现在”的条件下,“将来”与“过去”独立的特性称为马尔可夫性,具有这种性质的随机过程叫做马尔可夫过程。荷花池中一只青蛙的跳跃是马尔可夫过程的一个形象化的例子。青蛙依照它瞬间或起的念头从一片荷叶上跳到另一片荷叶上,因为青蛙是没有记忆的,当现在所处的位置已知时,它下一步跳往何处和它以往走过的路径无关。如果将荷叶编号并用X0,X1,X2,…分别表示青蛙最初处的荷叶号码及第一次、第二次、……跳跃后所处的荷叶号码,那么{Xn,n≥0} 就是马尔可夫过程。液体中微粒所作的布朗运动,传染病受感染的人数,原子核中一自由电子在电子层中的跳跃,人口增长过程等等都可视为马尔可夫过程。还有些过程(例如某些遗传过程)在一定条件下可以用马尔可夫过程来近似。 3.什么是马尔科夫随机场 马尔可夫随机场(Markov Random Field)包含两层意思。 马尔可夫性质:它指的是一个随机变量序列按时间先后关系依次排开的时候,第N+1时刻的分布特性,与N时刻以前的随机变量的取值无关。拿天气来打个比方。如果我们假定天气是马尔可夫的,其意思就是我们假设今天的天气仅仅与昨天的天气存在概率上的关联,而与前天及前天以前的天气没有关系。其它如传染病和谣言的传播规律,就是马尔可夫的。 随机场:当给每一个位置中按照某种分布随机赋予相空间的一个值之后,其全体就叫做随机场。我们不妨拿种地来打个比方。其中有两个概念:位置(site),相空间(phase space)。“位置”好比是一亩亩农田;“相空间”好比是种的各种庄稼。我们可以给不同的地种上不同的庄稼,这就好比给随机场的每个“位置”,赋予相空间里不同的值。所以,俗气点说,随机场就是在哪块地里种什么庄稼的事情。 马尔可夫随机场:拿种地打比方,如果任何一块地里种的庄稼的种类仅仅与它邻近的地里种的庄稼的种类有关,与其它地方的庄稼的种类无关,那么这些地里种的庄稼的集合,就是一个马尔可夫随机场。 二.数学描述 1.定义 马尔可夫链是随机变量X1,X2,X3...的一个数列。这些变量的范围,即他们所有可能取值的集合,被称为“状态空间”,而Xn的值则是在时间n的状态。如果Xn + 1对于过去状态的条件概率分布仅是Xn的一个函数,则 这里x为过程中的某个状态。上面这个恒等式可以被看作是马尔可夫性质。 2.性质 可还原性 马尔可夫链是由一个条件分布来表示的 这被称为是随机过程中的“转移概率”。这有时也被称作是“一步转移概率”。二、三,以及更多步的转移概率可以导自一步转移概率和马尔可夫性质: 同样, 这些式子可以通过乘以转移概率并求k ? 1次积分来一般化到任意的将来时间n + k。 周期性 边际分布 P(Xn)是在时间为n时的状态的分布。初始分布为P(X0)。该过程的变化可以用以下的一个时间步幅来描述: 这是Frobenius-Perron equation的一个版本。这时可能存在一个或多个状态分布π满足 其中Y只是为了便于对变量积分的一个名义。这样的分布π被称作是“平稳分布”(Stationary Distribution)或者“稳态分布”(Steady-state Distribution)。一个平稳分布是一个对应于特征值为1的条件分布函数的特征方程。 平稳分布是否存在,以及如果存在是否唯一,这是由过程的特定性质决定的。“不可约”是指每一个状态都可来自任意的其它状态。当存在至少一个状态经过一个固定的时间段后连续返回,则这个过程被称为是“周期的”。 重现性 各态历遍性 律动性 平稳状态分析和极限分布 可反转马尔可夫链 可反转马尔可夫链类似于应用贝叶斯定理来反转一个条件概率: 以上就是反转的马尔可夫链。因而,如果存在一个π,使得: 那么这个马尔可夫链就是可反转的。 这个条件也被称为细致平衡 (detailed balance)条件。 对于所有的i求和: 所以,对于可反转马尔可夫链,π总是一个平稳分布。 有限状态空间中的马尔可夫链 如果状态空间是有限的,则转移概率分布可以表示为一个具有(i,j)元素的矩阵,称之为“转移矩阵”: 对于一个离散状态空间,k步转移概率的积分即为求和,可以对转移矩阵求k次幂来求得。就是说,如果是一步转移矩阵,就是k步转移后的转移矩阵。 平稳分布是一个满足以下方程的向量 . 在此情况下,稳态分布π * 是一个对应于特征根为1的、该转移矩阵的特征向量。

spring boot修改代码后无需重启设置

1、配置jar包: <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> <version>1.2.6.RELEASE</version> </dependency> 2、设置运行参数: 如果针对代码的话,以上已经足够了。不过如果是静态文件的话,上面还不够。如果静态文件也要实现修改不重启,可以: 3、添加jar包: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <version>1.3.0.RELEASE</version> </dependency>

Android–多线程之Handler下载图片源码

Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不允许Activity新启动的线程访问该Activity里的UI组件,这样会导致新启动的线程无法改变UI组件的属性值。但实际开发中,很多地方需要在工作线程中改变UI组件的属性值,比如下载网络图片、动画等等。本篇博客主要介绍Handler是如何发送与处理线程上传递来的消息,并讲解Message的几种传递数据的方式,最后均会以小Demo来演示。 Handler Handler ,它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。 Handler主要有两个作用: 在工作线程中发送消息。在UI线程中获取、处理消息。 上面介绍到Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和sendMessage: Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。 从上面的各种方法可以看出,不管是post还是sendMessage都具有多种方法,它们可以设定Runnable对象和Message对象被入队到消息队列中,是立即执行还是延迟执行。 Post 对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。 在Handler中,关于Post方式的方法有: boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。boolean postAtTime(Runnable r,long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。boolean postDelayed(Runnable r,long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行void removeCallbacks(Runnable r):从消息队列中移除一个Runnable对象。 有一点值得注意的是,对于Post方式而言,它其中Runnable对象的run()方法的代码,均执行在UI线程上,所以对于这段代码而言,不能执行在UI线程上的操作,一样无法使用post方式执行,比如说访问网络,下面提供一个例子,使用post方式从互联网上获取一张图片,并且显示在ImageView中。 package com.bgxt.datatimepickerdemo; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; import android.widget.ImageView; public class HandlerPostActivity2 extends Activity { private Button btnDown; private ImageView ivImage; private static String image_path = "

Cesium学习笔记(4)

最近更新于2016/11/27 1.姿态与位置(orientation和position) Orientation: 若以正北为参照。 Heading:初始方向为正北,正角度为向东旋转,即水平旋转,也叫偏航角 Pitch:正角度为平面之上,负角度为平面之下,即前后旋转,也叫俯仰角 Roll:左右旋转,也叫翻滚角 具体解释:http://blog.csdn.net/yuzhongchun/article/details/22749521 Position: 关于position有多种类型,如SampledPositionProperty类型,是一个含有多个样本点位置的对象,主要用于动态轨迹生成,通过插值算法对轨迹进行插值,其中setInterpolationOptions方法用来设置插值方法与程度,它的某一时间的位置可以用position.getValue()方法获得,参数是朱利安时间 2.实体(Entity) model: minimumPixelSize与maximumScale组合可以控制模型远近时候的大小 availability: 代表该实体存在的有效时间,如下所示, availability : new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start : start, stop : stop })]), 3.图层(viewer.imageryLayers/viewer.scene. imageryLayers) 得到影像图层的集合,将其渲染到球体上,它是一个ImageryLayerCollection类型的,可以通过addImageryProvider()方法(返回值是ImageryLayer类型)进行添加,参数是各个provider(地图渲染引擎)。 viewer.imageryLayers.addImageryProvider(new Cesium.PieMapServerImageryProvider({ url: '//localhost:8082/service/v1/tile?map=dongsha', enablePickFeatures: false })); 4.大气、光照、雾效等环境特效 光照: scene.globe.enableLighting 雾效:scene.fog.enabled 大气:scene.skyAtmosphere 5.相机控制 Scene.ScreenSpaceCameraController:根据鼠标修改相机的方位,在里面可以选择是否禁用鼠标缩放、旋转等功能 关于flyto和setView的方式详见例子camera.html 6.时间控制 获取当前时间 var time = viewer.clock.currentTime; viewer.clock.onTick.addEventListener(function(clock){ //回调函数,时间变化就执行(即使停止时间轴仍然会执行。。。。) }) JulianDate:代表天文朱利安时间,用的是世界协调时,比北京时间晚8个小时,它有clone方法,可避免时间被修改 var start = Cesium.JulianDate.fromDate(new Date(2015, 2, 25, 16)); var stop = Cesium.JulianDate.addSeconds(start, 360, new Cesium.

MySQL数据类型 BLOB和TEXT

BLOB(Binary Large Object)是用来存储二进制大数据类型的。根据存储长度的不同,TEXT类型和BLOB类型都可细分为4种类型: TINYBLOB 最大长度为255(2^8–1)字节的BLOB列。 TINYTEXT 最大长度为255(2^8–1)字符的TEXT列。 BLOB[(M)] 最大长度为65,535(2^16–1)字节的BLOB列。 可以给出该类型的可选长度M。如果给出,则MySQL将列创建为最小的但足以容纳M字节长的值的BLOB类型。 TEXT[(M)] 最大长度为65,535(2^16–1)字符的TEXT列。 可以给出可选长度M。则MySQL将列创建为最小的但足以容纳M字符长的值的TEXT类型。 MEDIUMBLOB 最大长度为16,777,215(2^24–1)字节的BLOB列。 MEDIUMTEXT 最大长度为16,777,215(2^24–1)字符的TEXT列。 LONGBLOB 最大长度为4,294,967,295或4GB(2^32–1)字节的BLOB列。 LONGBLOB列的最大有效(允许的)长度取决于客户端/服务器协议中配置最大包大小和可用的内存。 LONGTEXT 最大长度为4,294,967,295或4GB(2^32–1)字符的TEXT列。 LONGTEXT列的最大有效(允许的)长度取决于客户端/服务器协议中配置最大包大小和可用的内存。 在大多数情况下,可以将BLOB类型的列视为足够大的VARBINARY类型的列。同样,也可以将TEXT类型的列视为足够大的VARCHAR类型的列。然而,BLOB和TEXT在以下几个方面又不同于VARBINARY和VARCHAR: 在BLOB和TEXT类型的列上创建索引时,必须制定索引前缀的长度。而VARCHAR和VARBINARY的前缀长度是可选的。 BLOB和TEXT类型的列不能有默认值。 在排序时只使用列的前max_sort_length个字节。 max_sort_length默认值为1024,该参数是动态参数,任何客户端都可以在MySQL数据库运行时更改该参数的值,例如: mysql> SET GLOBAL max_sort_length=2048; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@global.max_sort_length\G; *************************** 1. row *************************** @@global.max_sort_length: 2048 1 row in set (0.00 sec) mysql> SET max_sort_length=1536; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @@max_sort_length\G; *************************** 1. row *************************** @@max_sort_length: 1536 1 row in set (0.

程序员、架构师、技术经理、技术总监和CTO有啥区别?

程序员 程序员,英文名coder/programmer,大家常自嘲叫码农的阶段。这个角色职责是把需求或产品实现为用户可用的软件产品。 此职位为执行级别。另外因为经验较少,一般需要求助别人,或与别人一起完(ban)成(zhuan)一个任务。 此阶段大概要经历3年,程序员的职责如下: 1、负责公司运营系统的设计与开发工作 2、运营数据处理和分析 高级程序员 高级程序员学名工程师。到了这个level,英文名可改叫做engineer或developer。此时你的功力开始增强,这与你平时的积累努力是分不开的,祝贺你~ 此时的你不仅可以完成任务,开始注重代码的质量,能够写出工业级的代码。 你的经验可胜任模块级的系统设计,承担完成较为复杂的技术,能有效的自我管理,有帮助别人快速解决问题(trouble shooting)的能力。 此阶段你需要经历到7、8年左右的体验,中间要经历一段深刻自我历练的过程。 有时给人致命一击其实是心里的小蟊贼。一般人在5年前后遇到一个门槛,碰到天花板+彷徨期,或者你打心眼里不在喜欢编程,可尝试转为其它角色,如产品经理,售前售后支持等岗位,也不失为好选择。 当我们熬过这段儿,就会“山随平野尽,江入大荒流“,渐入佳境矣。 高级程序员定义软件功能、做开发计划推进和管理。可以带几个个帮手把产品规划的功能实现,你是团队中的”大手“,遇到难题也是你亲自攻艰克难。 所以,一个高级程序员,他的职责很清晰: 1、负责产品核心复杂功能的方案设计、编码实现 2、负责疑难BUG分析诊断、攻关解决 架构师 到了架构师级别,想必你已经学会降龙十八掌,可登堂入世,成为一位准(lao)专(you)家(tiao)。 我们大喊声:“单打独斗,老衲谁也不惧!“,遂开始领导一众技术高手,指点武功,来设计和完成一个系统,大多是分布式,高并发的系统架构平台。 架构师的任务是为公司产品的业务问题提供高质量技术解决方案。可能每条产品线都设置了架构师,也可能多条生产品线的的后端是由一个架构师设计的平台提供。 通过上面架构师的部分成果,总结其职责如下: 1、需求分析:“知彼”有时比“知已”还重要。管理市场,产品等的需求,确立关键需求。坚持技术上的优秀与需求的愿景统一,提升技术负债意识,提供技术选项,风险预判,工期等解决方案。 2、架构设计:在产品功能中抽取中非功能的需求,由关键需求变成概念型架构。列出功能树,分层治之,如用户界面层、系统交互层,数据管理层。达成高扩展,高可用,高性能,高安全,易运维,易部署,易接入等能力。 3、功能设计与实现:对架构设计的底层代码级别实现。如公共核心类,接口实现,应用发现规则、接口变更等。 技术经理 人生就是不断上升的过程,你已经到达经理的层次了。如今的你,需要不断提高领导力,需要定期召开团队会议讨论问题。 首先我们要更加自信,在工作中显示自己的功力,给讲话增添力量。如:“本次项目虽然有很大的困难,我们也需苦战到底。当然示先垂范,身先士卒,方能成功!” 技术经理有时候也可能叫系统分析员,一些小公司可能会整个公司或者部门有一个技术经理。技术经理承担的角色主要是系统分析、架构搭建、系统构建、代 码走查等工作,如果说项目经理是总统,那么技术经理就是总理。当然不是所有公司都是这样的,有些公司项目经理是不管技术团队的,只做需求、进度和同客户沟 通,那么这个时候的项目经理就好像工厂里的跟单人员了,这种情况在外包公司比较多。对于技术经理来说,着重于技术方面,你需要知道某种功能用哪些技术合 适,需要知道某项功能需要多长的开发时间等。同时,技术经理也应该承担提高团队整体技术水平的工作。 你需要和大家站在一起,因为人们也都有解决问题的能力,更需要有以下的能力与责任: 1、任务管理:开发工作量评估、定立开发流程、分配和追踪开发任务 2、质量管理:代码review、开发风险判断/报告/协调解决 3、效率提升:代码底层研发和培训、最佳代码实践规范总结与推广、自动化生产工具、自动化部署工具 4、技术能力提升:招聘面试、试题主拟、新人指导、项目复盘与改进 技术总监 如果一个研发团队超过20人,有多条产品线或业务量很大,这时已经有多个技术经理在负责每个业务,这时需要一位技术总监。 技术总监的职责: 1、组建平台研发部,与架构师共建软件公共平台,方便各条产品业务线研发。 2、通过技术平台、通过高一层的职权,管理和协调公司各个部门与本部门各条线。现在每个产品线都应该有合格的技术经理和高级程序员。 CTO 首席技术官,英文名Chief Technology Officer。是与CEO、COO、CFO同级的领导者,是技术和业务融合的领袖。 国内与国外对CTO的定义有些许不同。 美国对CTO的职责是设计公司三年内的产品和服务的技术发展方向,较少参与技术团队的日常管理和项目管理事务。基本是前瞻性的策略思维,比如Google的谢尔盖.布林一直保持对技术方向的敏锐,比如无人驾驶汽车,人工智能等走向。 在国内,CTO大部分则偏重于研发管理,相当于技术总监的Plus版。它相当于美国互联网公司常设的工程师副总裁+CTO的工作并集。但总体事情比美国的CTO层次低,大部分CTO的是领导技术团队开发各类产品,解决技术问题,管理不同的项目,排期交付。还有一部分的职能类似于架构师或总工程师,作为技术侧的权威,为下一步的发展方向 做研究探讨,为CEO提供建设型决定参考。 CTO的职责如下列表: 1、技术愿景:识别新技术、利用新技术、整合新技术、驱动新技术。驱动商业战略、驱动产品战略 2、技术架构:建立主营业务中的技术架构与实施模式,建立技术体系标准 3、流程制度:建立高质量,高效率的技术团队。健全的项目管理体系;完善的员工能力发展体系 4、知识培训:建立以研发内容为主的知识库管理体系、技术分享与技术文化的体系 5、业务支撑:与其它部门的沟通协作,如HR、市场、BD、财务、客服等提供技术管理接口;在产品技术层面能够领先于业内同行 6、影响力:在公司内部与行业中具备一定影响力与口碑 7、视野&格局&执行力:看待问题全面,具有强大的学习力,具备技术前瞻力,敏锐的市场嗅觉,战略落地的能力 小结 CTO做的事情,是商业、产品、技术、管理、团队相平衡的综合统管,公司的技术研发方向与重点商业化的结果负责,激励员工,营造工程师文化。 而技术总监主要是协调团队内部各个资源,引入工具,和方法提升工作效率。 技术经理角色相对具体,绩效考核,产品落地,执行优胜劣汰的规则。 正像《少有人走的路》,每个人的成长路径都不同,但无一不是兴趣与使命驱动——无论你是程序员,技术经理,还是在CTO的角色。大家一起发挥潜力,去迎接不期而遇的挑战与胜利后的曼妙风光。

微信开发之access_token之坑

首先不得不提到access_token的分类,一是普通access_token,二是网页授权access_token。其中前者是用于调用微信提供的各种借口,作为开发者的调用凭证,一般有效期为7200S,获取次数受限;另一种是第三方网页若需要使用用户微信账户登录,需要获取该access_token从而来获取用户微信账户信息。这个一定得区分开。 另外获取用户微信账户信息也有两种情况,一是普通的获取用户信息,它只需要调用微信用户信息接口即可获取,因而使用到的是第一种普通access_token,另一种就是上面提到的网页授权时获取用户信息。一旦二者概念混淆,则会报出invalid access_token错误。 对于第一种普通access_token,需要注意到的是,它是全局性的,就是一旦获取到了新的access_token,原有的access_token就会失效,而无法调用相关接口。而这种特性,导致的情况是,多个不同进程相互独立获取access_token时,会直接影响到其他进程调用相关微信接口,这种异常通常对应着 access_token失效异常。 为了解决这种情况,必须独立启动一个线程定时去获取access_token,并由该线程向所有其他线程提供该access_token,从而避免access_token获取混乱导致的失效问题。我实现该想法的方式是采用timer定时器,定时刷新获取access_token,并将其存入到指定property文件中,其他线程通过读取该文件中的access_token值,来调用相关接口。 @Controller @RequestMapping(value = "/timer") public class AcessTokenTimer { private static final String APPID = "*************"; private static final String APPSECRET = "*********"; private Timer timer = new Timer(true); @PostConstruct public void setToken(){ if(null == timer){ timer = new Timer(true); } timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { SystemUtil.setString("token.properties","access_token", UrlGETUtil.GET("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APPID+"&secret="+APPSECRET).getString("access_token")); }catch (Exception e){ e.printStackTrace(); } } },0,3600*1000); } } 在定时器任务中获取和写入access_token值。该类基于SpringMVC框架,此处用到了@PostConstruct标签,它的作用是,在Spring框架初始化完成之后,及执行对应方法体,直白地说就是开机自启。

volatile和synchronized的区别

volatile和synchronized特点 首先需要理解线程安全的两个方面:执行控制和内存可见。 执行控制的目的是控制代码执行(顺序)及是否可以并发执行。 内存可见控制的是线程执行结果在内存中对其它线程的可见性。根据Java内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地(CPU缓存),操作完成后再把结果从线程本地刷到主存。 synchronized关键字解决的是执行控制的问题,它会阻止其它线程获取当前对象的监控锁,这样就使得当前对象中被synchronized关键字保护的代码块无法被其它线程访问,也就无法并发执行。更重要的是,synchronized还会创建一个内存屏障,内存屏障指令保证了所有CPU操作结果都会直接刷到主存中,从而保证了操作的内存可见性,同时也使得先获得这个锁的线程的所有操作,都happens-before于随后获得这个锁的线程的操作。 volatile关键字解决的是内存可见性的问题,会使得所有对volatile变量的读写都会直接刷到主存,即保证了变量的可见性。这样就能满足一些对变量可见性有要求而对读取顺序没有要求的需求。 使用volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操作的原子性,但需要特别注意, volatile不能保证复合操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。 在Java 5提供了原子数据类型atomic wrapper classes,对它们的increase之类的操作都是原子操作,不需要使用sychronized关键字。 对于volatile关键字,当且仅当满足以下所有条件时可使用: 1. 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。 2. 该变量没有包含在具有其他变量的不变式中。 volatile和synchronized的区别 volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化 如果想更好地理解这两个关键字的作用,强烈建议看一下这篇文章:Java内存模型

Mockito&PowerMockito实战

本文包含了一些我个人认为使用Mockito和PowerMockito可能碰到的问题的解决方法(以下所有代码的运行前提是你已经配置好Mockito,PowerMockito的jar包) ------------------------------------------------------------------------------------------------------------------------------------------------------------------ package com.ray.mockito_demo1.present; import static org.mockito.Mockito.*; import java.util.Iterator; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; import com.ray.entity.Goods; @RunWith(MockitoJUnitRunner.class) public class MockitoTest { /** * 初始测试数据 */ @Before public void setUp() { // 初始化mock测试数据 g1 = mock(Goods.class); list = mock(List.class); when(g1.getName()).thenReturn("iPhone10s plus"); when(list.size()).thenReturn(1); when(list.get(0)).thenReturn(g1); } /** * 测试 List.class */ @Test public void testList() { // execute 执行测试方法 int size = list.size(); for (int i = 0; i < size; i++)

如何设计一个秒杀系统

什么是秒杀 秒杀场景一般会在电商网站举行一些活动或者节假日在12306网站上抢票时遇到。对于电商网站中一些稀缺或者特价商品,电商网站一般会在约定时间点对其进行限量销售,因为这些商品的特殊性,会吸引大量用户前来抢购,并且会在约定的时间点同时在秒杀页面进行抢购。 秒杀系统场景特点 秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增。 秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。秒杀业务流程比较简单,一般就是下订单减库存。 秒杀架构设计理念 限流: 鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。 削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。 异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。 内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。 可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了。像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。 架构方案 一般秒杀系统架构 设计思路 将请求拦截在系统上游,降低下游压力:秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。 充分利用缓存:利用缓存可极大提高系统读写速度。 消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。 前端方案 浏览器端(js): 页面静态化:将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。 禁止重复提交:用户提交之后按钮置灰,禁止重复提交 用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流 后端方案 服务端控制器层(网关层) 限制uid(UserID)访问频率:我们上面拦截了浏览器访问的请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。 服务层 上面只拦截了一部分访问请求,当秒杀的用户量很大时,即使每个用户只有一个请求,到服务层的请求数量还是很大。比如我们有100W用户同时抢100台手机,服务层并发请求压力至少为100W。 采用消息队列缓存请求:既然服务层知道库存只有100台手机,那完全没有必要把100W个请求都传递到数据库啊,那么可以先把这些请求都写到消息队列缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。 利用缓存应对读请求:对类似于12306等购票业务,是典型的读多写少业务,大部分请求是查询请求,所以可以利用缓存分担数据库压力。 利用缓存应对写请求:缓存也是可以应对写请求的,比如我们就可以把数据库中的库存数据转移到Redis缓存中,所有减库存操作都在Redis中进行,然后再通过后台进程把Redis中的用户秒杀请求同步到数据库中。 数据库层 数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。 案例:利用消息中间件和缓存实现简单的秒杀系统 Redis是一个分布式缓存系统,支持多种数据结构,我们可以利用Redis轻松实现一个强大的秒杀系统。 我们可以采用Redis 最简单的key-value数据结构,用一个原子类型的变量值(AtomicInteger)作为key,把用户id作为value,库存数量便是原子变量的最大值。对于每个用户的秒杀,我们使用 RPUSH key value插入秒杀请求, 当插入的秒杀请求数达到上限时,停止所有后续插入。 然后我们可以在台启动多个工作线程,使用 LPOP key 读取秒杀成功者的用户id,然后再操作数据库做最终的下订单减库存操作。 当然,上面Redis也可以替换成消息中间件如ActiveMQ、RabbitMQ等,也可以将缓存和消息中间件 组合起来,缓存系统负责接收记录用户请求,消息中间件负责将缓存中的请求同步到数据库。 参考文档:https://my.oschina.net/xianggao/blog/524943

js跳转/滚动到页面最底部

实现跳转到页面底部,要使用到body的scrollTop属性 先计算页面最底部div距离屏幕顶部的距离,与屏幕的高度相减,最后赋给scrollTop就可以了。 下面是示例代码: $('body').scrollTop( $('.bottom').offset().top - $(window).height() ); 如果要实现滚动效果,就要使用jQuery的animate动画方法 $('body').animate({ scrollTop: $('.bottom').offset().top - $(window).height() }, 500); 页面会在500毫秒内滚动到页面最底部 转载于:https://my.oschina.net/xuezhiyuan/blog/749286

adb 定时重启手机批处理bat

adb 定时重启手机批处理bat ---------------------------- for /l %%i in (1,1,100000) do ( @echo %%i adb reboot ping -n 120 127.0.0.1 > nul ) pause ---------------------------- %%i的值从1步进1到80 120 表示120秒 这个批处理bat作用是两分钟重启一遍手机。

android系统资源预加载和缓存原理分析

一、系统资源预加载 android系统资源加载分两种方式,预加载和使用进程中加载。 预加载是在zygote进程启动的时候被执行,一般系统中多应用共享的资源会被列为预加载资源,预加载的好处在于系统只在zygote执行一次加载操作,所有应用用到该资源不需要再重新加载,减少资源加载耗时。 有哪些资源会被zygote进程加载? framework中将会被系统多个应用进程共享的资源添加到res/values/array.xml中数组资源中,名为preload_drawable、preload_color_states_list, 如果有这些资源会被多个应用共享,可以将其添加到res/values/array.xml数组中,避免每个应用进程都去加载资源。 预加载的原理很简单,就是在zygote进程启动后将资源读取出来,保存到Resources一个全局静态变量中,下次读取系统资源的时候优先从静态变量中查找。主要代码在zygoteInit.java类中方法preloadResources(),主要代码如下: mResources = Resources.getSystem(); mResources.startPreloading(); if (PRELOAD_RESOURCES) { Log.i(TAG, "Preloading resources..."); long startTime = SystemClock.uptimeMillis(); TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int N = preloadDrawables(runtime, ar); ar.recycle(); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); addBootEvent(new String("Zygote:Preload "+ N + " obtain resources in " + (SystemClock.uptimeMillis() - startTime) + "ms")); startTime = SystemClock.uptimeMillis(); ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(runtime, ar); ar.

Android自定义刻度尺的实现思路以及步骤

最近一直在学自定义view,博大精深,感觉如果向底层看的话,功力不够且时间不允许,所以一直都是停留在怎么实现自定义view上,而为何会这么实现以及差异并没有考虑的很清晰,因为面向对象编程以及封装,都是让我们将功能抽出来使用,而不是去考虑每个功能里是怎么实现的,所以很苦恼,还是先实现吧,至于原理慢慢理解吧! 这是自定义View学习的第三篇,学习主要是在项目的基础上来学,并不是一点点的基础死扣,因为你看懂,敲出来一个自定义view的代码,你就会慢慢有所理解,包括中间的一些计算,所以还是建议大家先去敲代码,自己写不出来,就把别人的代码敲一遍,去理解一遍,比仅仅去看会领悟的更多,这就有点书读百遍,其义自现的意思,哈哈,一点浅见,谁让我笨呢。 今天讲一下自定义刻度尺的实现,咋听刻度尺,难度并不高,但是对于刚刚开始动手敲,摆脱Ctrl+c/Ctrl+z的同学来说还是有些难度的。 看看我的实现效果吧: 横向显示10cm,模拟器暂时找不到横屏,就这样吧!@_@ 思路呢? 刚开始敲的时候,先明确思路,磨刀不误砍柴工,进去就敲最后敲得自己也糊涂了! 1:画刻度尺 2:画刻度数 3:画红线标记 4:处理滑动 画刻度尺 canvas.save(); for (int i = min; i < max; i++) { if (i % 10 == 0) { //起点x坐标10像素,画厘米线 canvas.drawLine(10, 0, 10, 72, mLinePaint); String text = i / 10 + ""; Rect rect = new Rect(); float txtWidth = mTextPaint.measureText(text); mTextPaint.getTextBounds(text, 0, text.length(), rect); canvas.drawText(text, 10 - txtWidth / 2, 72 + rect.height() + 10, mTextPaint); } else if (i % 5 == 0) { //每隔0.

人脸识别之人脸识别技术综述

参考:http://www.xuehuile.com/thesis/9a81f680054441ad907934b07b465c8e.html,本文做了相关修改。 1 人脸识别技术概述 近年来,随着计算机技术的迅速发展,人脸自动识别技术得到广泛研究与开发,人脸识别成为近30年里模式识别和图像处理中最热门的研究主题之一。人脸识别的目的是从人脸图像中抽取人的个性化特征,并以此来识别人的身份。一个简单的自动人脸识别系统,包括以下4个方面的内容 : (1)人脸检测(Detection):即从各种不同的场景中检测出人脸的存在并确定其位置。 (2)人脸规范化(Normalization):校正人脸在尺度、光照和旋转等方面的变化。或者叫做alignment,人脸对齐,人脸校准 (3)人脸校验(Face verification ):采取某种方式表示检测出人脸和数据库中的已知人脸,确认两张脸是否是同一个人。 (4)人脸识别(Recognition):将待识别的人脸与数据库中的已知人脸比较,得出给你的脸是库里的谁。 2 人脸识别算法的框架 人脸识别算法描述属于典型的模式识别问题,主要有在线匹配和离线学习两个过程组成,如图1所示。 图1 一般人脸识别算法框架 在人脸识别中,特征的分类能力、算法复杂度和可实现性是确定特征提取法需要考虑的因素。所提取特征对最终分类结果有着决定性的 影响 。分类器所能实现的分辨率上限就是各类特征间最大可区分度。因此,人脸识别的实现需要综合考虑特征选择、特征提取和分类器设计。 3 人脸识别的发展历史及分类 人脸识别的研究已经有相当长的历史,它的发展大致可以分为四个阶段: 第一阶段:人类最早的研究 工作至少可追朔到二十世纪五十年代在心理学方面的研究和六十年代在工程学方面的研究。 J. S. Bruner于1954年写下了关于心理学的 The perception of people,Bledsoe在1964年就工程学写了Facial Recognition Project Report,国外有许多学校在研究人脸识别技术 [1],其中有从感知和心理学角度探索人类识别人脸机理的,如美国Texas at Dallas大学的Abdi和Tool小组 [2、3],由Stirling大学的Bruce教授和Glasgow大学的Burton教授合作领导的小组等 [3];也有从视觉机理角度进行研究的,如英国的Graw小组 [4、5]和荷兰Groningen大学的Petkov小组 [6]等。 第二阶段:关于人脸的机器识别研究开始于二十世纪七十年代。 Allen 和Parke 为代表,主要研究人脸识别所需要的面部特征。研究者用计算机实现了较高质量的人脸灰度图模型。这一阶段工作的特点是识别过程全部依赖于操作人员,不是一种可以完成自动识别的系统。 第三阶段:人机交互式识别阶段。 Harmon 和Lesk 用几何特征参数来表示人脸正面图像。他们采用多维特征矢量表示人脸面部特征,并设计了基于这一特征表示法的识别系统。Kaya和Kobayashi 则采用了统计识别方法,用欧氏距离来表征人脸特征。但这类方法需要利用操作员的某些先验知识,仍然摆脱不了人的干预。 第四阶段:20世纪90年代以来,随着高性能计算机的出现,人脸识别方法有了重大突破,才进入了真正的机器自动识别阶段。在用静态图像或视频图像做人脸识别的领域中,国际上形成了以下几类主要的人脸识别方法: 1)基于几何特征的人脸识别方法 基于几何特征的方法是早期的人脸识别方法之一 [7]。常采用的几何特征有人脸的五官如眼睛、鼻子、嘴巴等的局部形状特征。脸型特征以及五官在脸上分布的几何特征。提取特征时往往要用到人脸结构的一些先验知识。识别所采用的几何特征是以人脸器官的形状和几何关系为基础的特征矢量,本质上是特征矢量之间的匹配,其分量通常包括人脸指定两点间的欧式距离、曲率、角度等。 基于几何特征的识别方法比较简单、容易理解,但没有形成统一的特征提取标准;从图像中抽取稳定的特征较困难,特别是特征受到遮挡时; 对较大的表情变化或姿态变化的鲁棒性较差。 2)基于相关匹配的方法 基于相关匹配的方法包括模板匹配法和等强度线方法。 ①模板匹配法:Poggio和Brunelli [10]专门比较了基于几何特征的人脸识别方法和基于模板匹配的人脸识别方法,并得出结论:基于几何特征的人脸识别方法具有识别速度快和内存要求小的优点,但在识别率上模板匹配要优于基于几何特征的识别方法。 ②等强度线法:等强度线利用灰度图像的多级灰度值的等强度线作为特征进行两幅人脸图像的匹配识别。等强度曲线反映了人脸的凸凹信息。这些等强度线法必须在背景与头发均为黑色,表面光照均匀的前提下才能求出符合人脸真实形状的等强度线。 3)基于子空间方法 常用的线性子空间方法有:本征子空间、区别子空间、独立分量子空间等。此外,还有局部特征分析法、因子分析法等。这些方法也分别被扩展到混合线性子空间和非线性子空间。 Turk等 [11]采用本征脸( Eigenfaces)方法实现人脸识别。由于每个本征矢量的图像形式类似于人脸,所以称本征脸。对原始图像和重构图像的差分图像再次进行K-L变换,得到二阶本征空间,又称二阶本征脸 [12]。Pentland等 [13]提出对于眼、鼻和嘴等特征分别建立一个本征子空间,并联合本征脸子空间的方法获得了好的识别结果。Shan等 [14]采用特定人的本征空间法获得了好于本征脸方法的识别结果。Albert等 [15]提出了TPCA(Topological PCA)方法,识别率有所提高。Penev等 [16]提出的局部特征分析(LFA Local Feature Analysis)法的识别效果好于本征脸方法。当每个人有多个样本图像时,本征空间法没有考虑样本类别间的信息,因此,基于线性区别分析(LDA Linear Discriminant Analysis ),Belhumeur等 [17]提出了Fisherfaces方法,获得了较好的识别结果。Bartlett等 [18]采用独立分量分析(ICA,Independent Component Analysis)的方法识别人脸,获得了比PCA方法更好的识别效果。

Android应用程序访问linux驱动第二步:实现并测试hardware层

不管是出于什么样地考虑,android系统终究是提供了hardware层来封装了对Linux的驱动的访问,同时为上层提供了一个统一的硬件接口和硬件形态。 一.Hardware概述 在Hardware层中的一个模块中,主要设计一下三个结构: struct hw_module_tstruct hw_module_methods_tstruct hw_device_t 这三个结构体的关系是这样的:我们在上层访问linux驱动时,需要首先获得hardware层的对应的module,使用hw_get_module()方法实现,这个函数通过给定模块的ID来寻找硬件模块的动态链接库,找到后使用load()函数打开这个库,并通过一个固定的符号:HAL_MODULE_INFO_SYM寻找hw_module_t结构体,我们会在hw_module_t结构体中会有一个methods属性,指向hw_module_methods_t结构体,这个结构体中会提供一个open方法用来打开模块,在open的参数中会传入一个hw_device_t**的数据结构,这样我们就可以把对模块的操作函数等数据保存在这个hw_device_t结构中,这样,这样用户可以通过hw_device_t来和模块交互。 具体的说,我们在上层可以这样调用HAL层的module: xxx_module_t *module; hw_get_module(XXXID,(struct hw_module_t **)&module); 以上两步我们就获得了对应ID的 hw_module_t结构体。 struct xxx_device_t *device; module->methods->open(module,XXXID,(struct hw_device_t **)&device); 这样我们就获得了hw_device_t结构体,通过hw_device_t结构体我们就可以访问HAL层对应的module了。 这个思路很重要,后面我们测试我们的HAL层module的时候,就需要上面的代码。 整个过程可用一张图展示: 二.使用Android HAL规范封装对Linux驱动的访问 在hardware/libhardware/modules新建hellotest目录,添加两个文件:hellotest.c 和 Android.mk 1.hellotest.c 这个文件把对linux驱动的访问封装成了Android要求的格式。 #include <hardware/hardware.h> #include <hardware/hellotest.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #define DEVICE_NAME "/dev/hello" #define MODULE_NAME "HelloTest" #define MODULE_AUTHOR "jinwei" #define LOG_TAG "HelloTest" /* 定义LOG */ #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__) #define LOGI(.

采用带头节点的单链表保存单词,返回两个链表共同后缀的起始位置

这里数据域设为int类型,其实String也是一样的 思路一: 1.对于链表str1和str2,分别求出两个链表的长度m和n, 2。p指向str1的头节点,q指向str2的头节点,当m大于等于n,p向后移动m-n+1个节点,当n大于m,q向后移n-m+1,总之,要保证p和q所指的节点到链表尾的长度相等。 3.反复将指针p和q同步后移,并判断它们是否指向同一个节点,若指向同一点,则返回共同后缀的起始位置 </pre><pre name="code" class="java">package pac1; class Node{ public Node next; //指针域 public int data; //数据域 public Node(int data) { this.data = data; } public void show(){ System.out.print(data+" "); } } public class LinkList { public Node head; //头节点 public LinkList(){ this.head=null; } //头插法创建表,将新节点插入到头结点之后 public void creatList1(LinkList L,int [] arr){ for(int i=0;i<arr.length;i++){ Node node=new Node(arr[i]); //创建一个新节点 node.next = head; head = node; } } //尾插法创建表 public void creatList2(LinkList L,int [] arr){ addHeadNode(arr[0]);//将第一个元素作为头结点 Node rear=head; for(int i=1;i<arr.

八皇后问题求解——之递归

八皇后问题 八皇后问题 八皇后为题概述解决八皇后为题的步骤完整代码 1.八皇后为题概述 什么是八皇后问题? 该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击。 所以,我们要了解皇后的攻击模式:皇后可以横着走任意步数、竖着走任意步数、斜着走任意步数。 翻译过来就是:即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。(实际上,总共有 92种摆法 ) 例如,下面的这种摆法(0表示没有皇后,1表示摆放了皇后): 1000000000100000000010000000001000010000010000000000010000000001 2.解决八皇后为题的步骤 1.八皇后的存储问题2.八皇后的打印3.八皇后的和平相处(如何判断该位置是否可以放置一个皇后)4.如何进行递归 问题1:八皇后的存储问题 八皇后为8*8的格式,为了节约内存,我们可以将棋盘定义为unsigned char chess[8](当然char chess[8]也没问题) 为什么呢?char类型为8bit,所以总共就有8*8bit,其中,我们让有皇后的位置标记为1,让没有皇后的位置标记为0 问题2:八皇后的打印 我们把八皇后的打印单独写一个函数,模块化方便定位错误。 int count=0;//累积八皇后的方案个数,是一个全局变量 void Eight_Queen_Print(unsigned char *chess){ printf("No.%d\n",count); for(int i=0;i<8;++i){ for(int j=0;j<8;++j){ printf("%c ",chess[i] & (1<<(7 & ~j))?'1':'0'); } putchar('\n'); } putchar('\n'); } 打印出来的格式可能是: No.92 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0

大数据面试题

Big Data 面试题总结 JAVA相关 1-1)List 与set 的区别? 老掉牙的问题了,还在这里老生常谈:List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重复。 1-2)数据库的三大范式? 原子性、一致性、唯一性 1-3)java 的io类的图解 1-4)对象与引用对象的区别 对象就是好没有初始化的对象,引用对象即使对这个对象进行了初始化,这个初始化可以使自己的直接new的也可以是直接其他的赋值的,那么背new或者背其他赋值的我们叫做是引用对象,最大的区别于 1-5)谈谈你对反射机制的理解及其用途? 反射有三种获取的方式,分别是:forName / getClass / 直接使用class方式 使用反射可以获取类的实例 1-6)列出至少五种设计模式 设计方式有工厂法,懒加载,观察者模式,静态工厂,迭代器模式,外观模式、、、、 1-7)RPC 原理? Rpc分为同步调用和一部调用,异步与同步的区别在于是否等待服务器端的返回值。Rpc的组件有RpcServer,RpcClick,RpcProxy,RpcConnection,RpcChannel,RpcProtocol,RpcInvoker等组件, 1-8)ArrayList、Vector、LinkedList 的区别及其优缺点?HashMap、HashTable 的区别及优缺点? ArrayList 和 Vector 是采用数组方式存储数据的,是根据索引来访问元素的,都可以 根据需要自动扩展内部数据长度,以便增加和插入元素,都允许直接序号索引元素,但 是插入数据要涉及到数组元素移动等内存操作,所以索引数据快插入数据慢,他们最大 的区别就是 synchronized 同步的使用。 LinkedList 使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但 是插入数据时只需要记录本项的前后项即可,所以插入数度较快! 如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用 Vector 或 ArrayList 都可以。如果是对其它指定位置的插入、删除操作,最好选择 LinkedList HashMap、HashTable 的区别及其优缺点: HashTable 中的方法是同步的 HashMap 的方法在缺省情况下是非同步的 因此在多线程环境下需要做额外的同步机制。 HashTable 不允许有 null 值 key 和 value 都不允许,而 HashMap 允许有 null 值 key和 value 都允许 因此 HashMap 使用 containKey()来判断是否存在某个键。

Android Multimedia框架总结(八)Stagefright框架之AwesomePlayer及数据解析器

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52503057 前言:前面一篇分析了mediaplayerservice及MediaPlayer中的CS模型,但是对于如何能把数据解析出来,渲染到最终的SurfaceView上显示,并且播放起来,我们依然还不得而知,从今天开始,就开始介绍多媒体框架中数据解析->解码->渲染输出过程,也就是后面几篇都要介绍的stagefright框架。 先看下今天的Agenda: Stagefright的整体结构中角色Stagefright在playback中角色Stagefright初识StagefrightPlayer及AwesomePlayer初识MediaExtractor数据解析流程 Stagefright的整体结构中角色 Stagefright在playback中角色 Stagefright初识 前面一篇中,分析到mediaplayerservice会调到Stagefright中,进行编码解码操作 在libsstagefright中,预设的多媒体解码是openCore,由于其过于庞大和复杂,需要成本较高,开始引进了另一个框架,也就是stagefright框架,以后默认情况android选择stagefright,但是并没有完全抛弃opencore,做了一个OMX层,仅仅是对 opencore的omx-component部分做了引用。stagefright是和opencore是并列的。Stagefright在 Android中是以shared library的形式存在(libstagefright.so),其中的module – AwesomePlayer可用来播放video/audio。 AwesomePlayer提供许多API,可以让上层的应用程序(Java/JNI)来调用。 先看下源头,从mediaplayerservice到Stagefright: 接着进入MediaPlayerFactory中的createPlayer方法中: 本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52503057 StagefrightPlayer及AwesomePlayer初识 开始进入StagefrightPlayer的构造函数 StageFrightPlayer中引用了AwesomePlayer,进而进行相关操作, 从上面代码可以看出,接着分析下StagefrightPlayer,如下代码: StagefrightPlayer继承了MediaPlayerInterface接口, 同样以setDataSource为例,通常我们负责的模块或调用别人的模块时,在模块和模块之间,相关于一个黑盒一样。里面什么流程我们并不清楚,call后,返回对应的状态或数据,仅此而已。 AwesomePlayer,就像是StagefrightPlayer中一个小盒子一样。 当mediaplayerservice中setDataSource传下来之后,进入如下方法: 以上代码总结为:所以执行步骤都会调用 mPlayer->setDataSource(xxxx),而在前面的分析,我们知道,这个mPlayer是被定义成AwesomePlayer,因为文件的setDataSoure及uri方式的setData仅在实现有些区别,接着向下看: 以上代码总结为:当setDataSource好后,返回上层OK状态, 再看下文件类型的setDataSource,如下: 以上代码总结为:匹配不同的文件类型,并用数据解析器处理,Mime表示该资源的媒体类型,当出现以右边格式出现的时候,就能被播放器识别,如经常手机中文件,单击时,就会弹出一个用哪个软件打开一样。列举一些常用的Mime类型的资源,如下: 本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52503057 MediaExtractor数据解析流程 接着,我们看下上面一直在用的MediaExtractor(数据解析器) 以上代码总结: 根据对文件解析的不同格式创建一个Extractor解析器,并解析,创建好解析器后,回到AwesomePlayer::setDataSource_l()中,继续执行setDataSource_l(extractor),对新建的这个解析器做处理,其实质是显示音视频A/V的分离。 setVideoSource(extractor->getTrack(i));//设置视频源mVideoTrack ; setAudioSource(extractor->getTrack(i));//设置音频源mAudioTrack; mVideoTrack和mAudioTrack的做为创建的AwesomePlay的成员函数,其类型为MPEG4Source,继承了MediaSource。 以上过程就进行了A\V的分离,对音频和视频资源进行分开处理,其过程是mediaplayerservice->Stagefrightplayer—>Awesomeplayer——>MPEG4Extractor——>MPEG4Source.这几个过程。StageFright的Parse,Decode过程下节分析。 第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。 如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易