Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15843 articles
Browse latest View live

HibernateTools实现pojo类 数据库schma mapping映射的相互转换 二

$
0
0

接着上一篇博客: HibernateTools实现pojo类 数据库schma mapping映射的相互转换


思路二:由数据库表,生成Mapping映射文件和POJO类。

   虽然可以实现,但个人觉着先设计数据库,然后再生成类不符合Hibernate的面对对象持久化的思维方式。好了,还是说步骤吧,首先在test数据库建立两张表,分别为course表和teacher表

-- ----------------------------
-- Table structure for course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
建好表后,在eclipse项目上右键-->new,如下图,选择框中的第三项,这个reveng.xml文件用于配置 选择要生成POJO类的数据库表。


选择上篇博客中创建的Console configuration项,点Database schema框下的refresh,之后可以看到test数据库,单击就出现了course和teacher表,全选后点击Include,之后点finish,如下图


再来到Hibernate Code Generation Configuration窗体,首先配置下Output directory输出目录,在尽挨着的复选框打上勾,然后在package栏写上生成文件要输出到哪个包,并选择刚配置好的reveng.xml文件


配置要输出的项,这里选定前两项,生成.java和.hbm.xml,就是我们想要的POJO类和Mapping映射文件。之后点击run就好了。


结果如下图:


生成的Mapping映射文件的代码

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><!-- Generated 2014-5-31 11:19:19 by Hibernate Tools 4.0.0 --><hibernate-mapping><class name="org.hibernate.test.Course" table="course" catalog="test"><id name="id" type="int"><column name="id" /><generator class="assigned" /></id><many-to-one name="teacher" class="org.hibernate.test.Teacher" fetch="select"><column name="teacherId" not-null="true" /></many-to-one><property name="name" type="string"><column name="name" /></property></class></hibernate-mapping>
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><!-- Generated 2014-5-31 11:19:19 by Hibernate Tools 4.0.0 --><hibernate-mapping><class name="org.hibernate.test.Teacher" table="teacher" catalog="test"><id name="id" type="int"><column name="id" /><generator class="assigned" /></id><property name="name" type="string"><column name="name" /></property><set name="courses" table="course" inverse="true" lazy="true" fetch="select"><key><column name="teacherId" not-null="true" /></key><one-to-many class="org.hibernate.test.Course" /></set></class></hibernate-mapping>

生成的POJO类:

package org.hibernate.test;

// Generated 2014-5-31 11:19:19 by Hibernate Tools 4.0.0

/**
 * Course generated by hbm2java
 */
public class Course implements java.io.Serializable {

	private int id;
	private Teacher teacher;
	private String name;

	public Course() {
	}

	public Course(int id, Teacher teacher) {
		this.id = id;
		this.teacher = teacher;
	}

	public Course(int id, Teacher teacher, String name) {
		this.id = id;
		this.teacher = teacher;
		this.name = name;
	}

	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public Teacher getTeacher() {
		return this.teacher;
	}

	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

package org.hibernate.test;

// Generated 2014-5-31 11:19:19 by Hibernate Tools 4.0.0

import java.util.HashSet;
import java.util.Set;

/**
 * Teacher generated by hbm2java
 */
public class Teacher implements java.io.Serializable {

	private int id;
	private String name;
	private Set courses = new HashSet(0);

	public Teacher() {
	}

	public Teacher(int id) {
		this.id = id;
	}

	public Teacher(int id, String name, Set courses) {
		this.id = id;
		this.name = name;
		this.courses = courses;
	}

	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set getCourses() {
		return this.courses;
	}

	public void setCourses(Set courses) {
		this.courses = courses;
	}

}

到此我们就完成了由数据库表生成POJO类和Mapping映射文件的过程


思路三:由Mapping映射文件生成数据库DDL和POJO类


首先,新建一个Mapping文件,这里在项目中建立Department.hbm.xml。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" ><hibernate-mapping><class name="org.hibernate.test.Department" table="DEPARTMENT"><id name="id" type="int"><column name="ID" /><generator class="increment"></generator></id><property name="name" type="java.lang.String"><column name="NAME" /></property></class></hibernate-mapping>

接下来建一个新的Console Configuration文件,基本配置和上文中配置的过程一样,最关键的是加入mapping文件。


接下来,改下Hibernate Code Generation Configuration就好了,首选选择新配置的Console Configuration文件


接下来选择要生成的Schema和.Java文件,然后run就可以了。


最终结果如图:


生成的DDL代码为

create table DEPARTMENT (ID integer not null, NAME varchar(255), primary key (ID));</span>

POJO类:

package org.hibernate.test;

// Generated 2014-5-31 16:23:27 by Hibernate Tools 4.0.0

/**
 * Department generated by hbm2java
 */
public class Department implements java.io.Serializable {

	private int id;
	private String name;

	public Department() {
	}

	public Department(String name) {
		this.name = name;
	}

	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

    好了,至此POJO类,Mapping文件和数据库表相互转化就都介绍完了,当然这是借助eclipse的插件实现的,熟悉使用ant的朋友也可以借助ant脚本来实现,具体的教程去google吧。这里推荐下 HibernateTools的官方教程,包含了eclipse插件和ant脚本两种实现方式,非常全面。



作者:xqf309 发表于2014-5-31 22:27:37 原文链接
阅读:69 评论:4 查看评论

Oracle-SQL优化-union和union all

$
0
0
用union all替代union
Union因为要进行去除重复值的处理,所以效率要低
适用场合:1-如果合并两个select结果集,没有刻意要去除重复行
          2-如果union的各个select结果集,不存在交集
Oracle的内部处理过程:
union操作:先执行union all操作获取所有数据合集,再执行去除重复行操作。所以如果没有重复的,不要用union,效率低


下面通过一个案例说明一下
Sql1:union联合两个结果集
select DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbinstcfl
union
select INTER_CODE as DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbbondcfl
执行计划如下图:一共耗时6ms

Union操作:要先执行UNION-ALL操作获取结果集,再执行SORT-UNIQUE操作,看后面的时间,这个操作耗费2ms,如果数据量非常多的话,这个操作耗时和资源是非常惊人的。
Sql2:union all联合两个结果集
select DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbinstcfl
union all
select INTER_CODE as DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbbondcfl
执行计划如下图:一共耗时3ms

Union all操作:少了去除重复操作。去重复一项和上面比,就少了2ms,再看两个执行计划的最后一步整合数据,sql1用了2ms,sql2用了1ms,效率是不是高了很多

union和union all关键字需要注意的问题是:
union 和 union all都可以将多个结果集合并,而不仅仅是两个,你可以将多个结果集串起来。
使用union和union all必须保证各个select 集合的结果有相同个数的列,并且每个列的类型是一样的。但列名则不一定需要相同,oracle会将第一个结果的列名作为结果集的列名。例如下面是一个例子:

select empno,ename from emp
union
select deptno,dname from dept
我们没有必要在每一个select结果集中使用order by子句来进行排序,我们可以在最后使用一条order by来对整个结果进行排序。例如:
select empno,ename from emp
union
select deptno,dname from dept
order by ename;

对多个结果集进行合并处理的关键字有union,union all,intersect,minus
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
Union All:对两个结果集进行并集操作,包括重复行,不进行排序;
Intersect:对两个结果集进行交集操作,不包括重复行,同时进行默认规则的排序;
Minus:对两个结果集进行差操作,不包括重复行,同时进行默认规则的排序。


对上面两个结果集进行intersect操作,
Sql3:
select DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbinstcfl
intersect
select INTER_CODE as DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbbondcfl
执行计划如下图:一共耗时7ms

对上面两个结果集进行intersect操作,
select DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbinstcfl
minus
select INTER_CODE as DEAL_SERIAL_NO,
       VERSION_NO,
       START_DATE,
       END_DATE,
       PERIOD,
       COMPD_METHOD
  from tbbondcfl
执行计划如下图:一共耗时7ms

总结:对两个结果集的union,union all,intersect,minus操作
耗时:
Union all:3ms
1.两个结果集的全表扫描获取2.获取所有展现数据
Union:6ms
1.两个结果集的全表扫描获取2.去除重复操作3.获取所有展现数据
Intersect:7ms
1.两个结果集的全表扫描获取2.两个结果集的唯一性排序3.获取交集4.获取所有展现数据
Minus:7ms
1. 两个结果集的全表扫描获取2.两个结果集的唯一性排序3.获取差集4.获取所有展现数据
Intersect和minus的获取交集和差集如执行计划图,没有耗费时间,这个内部机制没有研究,不过由于之前是唯一性排序,所以即使耗时也很少,就当做不耗时了

了解内部运行机制:优化一切尽在掌握



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



当个极客老爹:儿童节礼物选购指南

$
0
0

作者头像
作者: 钱雨沉/产品观察家
我是一个爱喵的文身胡子男。
[核心提示]6.1 儿童节来了,为家中小朋友买什么礼物才能又实用、又能凸显你极客老爹的范儿呢?

极客老爹买什么

一个靠谱的极客老爹会选择那些有品位,小朋友们特别喜欢,还能有教育意义的好玩意儿,如果你对儿童节买什么还没有头绪,请参考我们给你提供的几个备选吧。

万能的乐高

是的,乐高是万能的,无论是 星战、超级英雄( DC  Marvel 均有)还是 城市主题,你总能找到一款精美、复杂并且充满韵味的产品。当然了,更高阶的  Technic 系列和  Mindstorms 会演示那些复杂的机械传动结构与最有乐趣的机器人编程。

那个小朋友会不爱这样一辆精美的 乌尼莫克

EV3 套件可以拼装出无数承载了想象力与梦幻的各种机器人。

买一套乐高,你会看到家里的小朋友在一个月内都痴迷于这些方块,也会让他有兴趣接触机械、机器人、编程以及最重要的想象力与创造力。

一台独特的相机

很多影像大师都从童年的一台普通相机开始了他们的摄影艺术之旅。也许你家的小朋友是未来的波普艺术大师,那么今天最好为他提供一台够酷、够好用的相机。

OTTO 是一个基于树莓派、可以方便拍出 GIF 的相机,OTTO 不光外形漂亮,得益于采用了树莓派平台,你可以添加无数种玩法,比如给图片加上各种滤镜、贴图、文字、信息等等。这不光是一台相机,还是一个开源平台。

我们介绍过的 宝丽来数码那拍立得也值得考虑,这款不仅看起来想,长得也想 Instagram 图标(事实上 Instagram 图标就是一款宝丽来相机)一样的拍立得可以把拍摄的照片直接分享到社交网络,也能通过相纸打印出来。Android 系统和触摸屏允许你在相机上完成对照片的修饰与再加工。

儿童眼中的世界与我们的大不相同,你需要的就是给他一台相机,让他悉数记录下童年的光影,不管未来他与 PHP 打交道还是与镜头打交道,这份对生活与美的敏感,将是一生的良伴。

对科技的爱要从小培养

创客们已经做好了无数种适合各个年龄层、各种兴趣爱好的机器人套件了。今天就萎大家介绍两个,更多的选择可以自行去创客社区、或淘宝寻找。

创客们的玩具一般都是带电带火(焊接),对于年龄小的小朋友的确有点危险。所以我们给你推荐一款不用焊接也能学电路的好玩意—— 画笔电子学。利用导电画笔画出电路,元器件粘在纸板上,让小朋友们安全得体会到自己“绘制”电子电路的乐趣。小手电、电子警铃、闪烁的圣诞树都可以“画”出来。

如果觉得市面上的机器人套件有点昂贵,那么你可以选择  PVCBOT 系列,采用 PVC 塑料自己裁剪出机器人的骨架、外形,20 元就能买到一个套件自己拼装,价格低,乐趣不减。

既然小朋友喜欢机器人,那么买一套有趣儿童创客机器人套件,让他从中学习机械结构、电路和动手能力必然是最正确的选择。

音乐也要有趣才行

学钢琴是个痛苦的过程,如果你一定要你家孩子学琴,那么请选择这款能让学琴变得轻松一点、有趣一点的电钢琴。

目前你找不到 壹枱钢琴之外的选择了,这台 3999 的电钢琴不仅采用了配重琴键确保了琴键感,还在琴键上增加了一排互动灯帮助你学琴,练习指法。配合 iPad 上的 App,你可以像玩音游一样学习钢琴,体验音乐的乐趣。

学琴是个好事儿,但是别忘记音乐是给人带来美感的享受,你应该给家里的小朋友找到好的学习工具,尽可能去体验音乐带来的乐趣,提高学习的效率。

没有人不爱游戏

当我们小时候玩着口袋妖怪、怪物猎人长大的时候,千万别让自己的孩子玩着摩尔庄园长大!

如何防止自己家孩子沉迷垃圾网游?太简单了,给他玩更好的游戏,自然就有了判断力。掌机自然推荐任天堂出品,游戏轻松有趣,不乏各种美好善良;主机就在 PS4 与 XBOX ONE 中选一个吧。

最重要的是,你从此可以明目张胆的在家“陪孩子”打游戏了!

写在最后

当个极客老爹,并不仅限 6.1 这天:)

P.S.这篇极客老爹指南最良心的地方在于:推荐的所有玩意,其实也是你爱玩 :P 头图 来自

极客观察均为极客公园原创报道,转载请注明原文链接。

原文地址: http://www.geekpark.net/read/view/205689

关注极客公园,即时获得最新内容: Twitter | 微信:极客公园 | 新浪微博 | 花瓣网 | 人人小站 | Google+ | 点点

历数2013年优秀的开源游戏引擎与开源游戏项目

$
0
0
转载自:http://www.oschina.net/question/1250933_141230

2013年是移动游戏爆发的一年,也是开源游戏爆发的一年!在这里,我们历数一下2013年都有哪些优秀的开源游戏诞生,还有哪些优秀的开源游戏技术解决方案诞生!

开源跨平台2D客户端引擎 Cocos2d-x

MIT协议,Cocos2D-X是全球知名的开源跨平台手机游戏引擎,易学易用,目前已经支持iOS、Android、Windows8、Mac OSX、Linux、BlackBerry、Windows Phone等平台。Cocos2D-HTML5基于HTML5规范集开发,实现了引擎对浏览器的支持。现在cocos2d-x团队隶属于触控,据说触控要上市了。

cocos2d-x项目地址: http://www.oschina.net/p/cocos2d-x


开源游戏服务器端框架 Firefly

MIT协议,Firefly是免费、开源、稳定、快速扩展、能 “热更新”的分布式游戏服务器端框架,采用Python编写,业内小有名气,目前有几十家游戏开发团队在使用Firefly开发手机网游产品,十几款已上线产品,优势是国内最大的开源游戏社区 9秒社团 自研,所以游戏开发者的讨论交流活跃度的确是国内最高的,也是目前版本迭代频率最快的。

Firefly项目地址: http://www.oschina.net/p/firefly-game-server


开源游戏服务器端框架 pomelo

MIT协议,pomelo 是由 网易开发的基于 node.js开发的高性能、分布式游戏服务器框架, 也可作为高实时web应用框架。目前pomelo是基于node.js上做的优秀游戏服务器端框架,文档非常详细。

pomelo项目地址: http://www.oschina.net/p/pomelo


开源游戏地图编辑器MarbleMap

MIT协议,MarbleMap是一款as3开发的游戏地图编辑器,他免费开源,同时支持Cocos2d-x坐标系和AS3坐标系,功能丰富,不过是一款新推出的开源项目,较为年轻。

MarbleMap项目地址: http://www.oschina.net/p/marblemap-editor


开源卡牌手机网游《DiabloWorld》(中文名:暗黑世界)

MIT协议,频繁迭代的卡牌类手机网游开源项目,是国内第一款开源的卡牌手游项目。服务器端基于Firefly客户端基于cocos2d-x,20多个系统玩法,已经迭代了6个版本,并先后被上海专家组和北京专家组的不同地区开发者推出了U3D版本分支和AIR版本分支。

《暗黑世界》项目地址: http://git.oschina.net/9maio/diabloworld


开源45度RPG网页游戏《烽烟OL》

MIT协议,一款由Firefly+as3开发的网页游戏,30多个系统玩法,目前已经跟新到1.6版本,是一个很优秀的商品级开源项目,维护团队还是很友好的,所有问题几乎都会进行回答。

《烽烟OL》项目地址: http://git.oschina.net/9maio/fengyanOL


开源对战手机网游《进击的9秒》

MIT协议,一款强调布阵然后对战的手机网游,算是SRPG类型,团队战斗力强悍,不过文档少,目前已经有2款基于这款游戏修改出来的产品上线运营了!

《进击的9秒》项目地址: http://git.oschina.net/9maio/gamein9miao




杨粼波 2014-06-01 12:57 发表评论

HBase使用教程

$
0
0

1     基本介绍

1.1 前言

HBase – Hadoop Database,是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的 分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。

HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。

HBase是一个高 可靠性、高性能、面向列、可伸缩的 分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模 结构存储集群。

2     安装和使用

2.1 下载

HBase的官方网站http://www.apache.org/dyn/closer.cgi/hbase/上面可以下载到各种版本。目前用最新版本是0.98.2,建议下载stable目录下的稳定版本。

2.2 安装

安装依赖基础要求

1.   Linux操作系统

根据HBase的官方介绍,HBase没有在windows下测试过,因而,我们都是将HBase安装在Linux操作系统上。我本机安装的Ubuntu 12.04的虚拟机。

2.   Jdk

HBase需要jdk支持其运行,jdk版本要求是1.6及其以上。

这里暂且把Linux虚拟机的安装和虚拟机上jdk的安装过程跳过,可以参照网上其他相关资料执行。

HBase的安装方法比较简单,将我们下载的HBase的安装包hbase-0.94.20.tar.gz拷贝到Linux的根目录下。

接着执行以下命令和配置,之后启动HBase:

1.   解压缩安装包

root@ubuntu:/# tar xfz hbase-0.94.20.tar.gz

root@ubuntu:/# cd hbase-0.94.20

2.   配置数据存储目录

正如官方文档描述的那样,这时我们可以直接启动HBase,这样的话,使用的数据存储目录为 /tmp/hbase-${user.name},也就意味着,我们一旦重启Linux,我们先前存储的数据就将丢失。

Linux下执行以下命令:

root@ubuntu:/# cd /hbase-0.94.20/conf/

root@ubuntu:/hbase-0.94.20/conf# vi hbase-site.xml

之后,修改配置文件内容为:

<?xml version="1.0"?>

<?xml-stylesheet type="text/xsl"href="configuration.xsl"?>

<configuration>

  <property>

   <name>hbase.rootdir</name>

    <value>file:///hbase_data/hbase</value>

  </property>

</configuration>

3.   启动HBase

root@ubuntu:/hbase-0.94.20/conf# ../bin/start-hbase.sh

starting master, logging to/hbase-0.94.20/bin/../logs/hbase-root-master-ubuntu.out

至此,单机模式启动HBase已经完成了。HBase的停止脚本是相同目录下的stop-hbase.sh。

2.3 HBase安装模式

在上一节中我们提到,我们安装的是单机模式。单机模式表示,我们所有的服务都运行在一个JVM上,包括HBase和Zookeeper。

另外,HBase还有两种安装模式:伪分布式模式和分布式模式。

伪分布式模式是把进程运行在一台机器上,但不是一个JVM。

完全分布式模式就是把整个服务被分布在各个节点上了 。

伪分布式模式和分布式模式依赖安装较多其他组件和服务,安装过程较为复杂,将会在另一篇文章中专门介绍。

3     开始一个例子

大多数技术人员happy的时候开始了。我们开始一个简单的Helloworld。

3.1 使用HBase shell连接HBase

使用HBase自带的客户端连接工具,连接到HBase:

 

3.2 创建User表

输入以下命令并执行:

 

3.3 对User表简单地增删改查

往User表中插入一条信息:

 

 

查询刚才插入的信息:

 

 

3.4 检查数据存储目录

我们看一下之前我们配置的数据存储目录的变化:

 

我们可以看到,在之前配置的数据存储目录下,已经新添加了一些用于存储我们刚才存入的数据的文件了。

 

4     HBase基础定义和概念

4.1 表

HBase是一个数据库,数据以表的形式存储在Hbase中。

正如我们在hello world中定义中的User表类似,HBase的表的结构如下所示:

Row Key

Time Stamp

ColumnFamily contents

ColumnFamily anchor

"com.cnn.www"

t9

 

anchor:cnnsi.com = "CNN"

"com.cnn.www"

t8

 

anchor:my.look.ca = "CNN.com"

"com.cnn.www"

t6

contents:html = "<html>..."

 

"com.cnn.www"

t5

contents:html = "<html>..."

 

"com.cnn.www"

t3

contents:html = "<html>..."

 

4.2 行、列族、列

行以rowkey作为唯一标示。Rowkey是一段字节数组,这意味着,任何东西都可以保存进去,例如字符串、或者数字。行是按字典的排序由低到高存储在表中。

列族是列的集合。要准确表示一个列,需要“列族:列名”的方式。例如Hello world中的name列,应该被表示为“personalinfo:name”。

值得注意的是,列族被要求在创建表时指定,但列不需要,可以随时使用的时候创建。另外,一个列族的成员在文件系统上都存储在一起,因而列族中的所有列的存取方式都是一致的。HBase的存储优化就都针对列族级别,例如,我们可以考虑将经常需要一起取出来分析的信息,都存储在一个列族上。

5     HBase常用的操作

为了方便大家开发过程中快速查询,这里分类介绍最常见的HBase命令。HBase shell中支持的所有命令,可以通过help命令来列举出来。如下所示:

 

这里只是截取了前部分命令,尚有部分命令不能再上图中显示。

5.1 一般命令

5.1.1 status

功能:查询服务器状态

使用:

 

 

5.1.2 version

功能:查询HBase版本信息

使用:

5.1.3 whoami

功能:查看连接的用户

使用:

 

 

5.2 DDL命令

5.2.1 Create创建表

功能:创建一个表。正如之前提到的,创建一个表时,不指定具体的列名,但要指定列族名。

使用:create ‘表名’,’列族名1’,’列族名2’

 

5.2.2 disable失效表

功能:失效一个表。当需要修改表结构、删除表时,需要先执行此命令。

使用:

 

5.2.3 enable使失效表有效

功能:使表有效。在失效表以后,需要执行此命令,以使得表可用。

使用:

 

5.2.4 alter修改表结构

功能:修改表结构,包括新增列族、删除列族等

使用:

新增列族(记得在执行alter之前,要先disable表)

 

删除列族

 

 

重命名列族

列族不能被重命名。重命名一个列族的通常途径是使用API创建一个有着期望名称的新的列族,然后将数据复制过去,最后再删除旧的列族。

5.2.5 describe查看表结构

功能:查看表结构

使用:

 

 

5.2.6 list列举数据库中的所有表

功能:查看数据库中所有的表

使用:

 

 

5.2.7 drop删除表

功能:删除指定的表

使用:

 

5.3 DML命令

5.3.1 put插入数据

功能:插入一条数据到指定的表中。对于同一个rowkey,如果执行两次put,则第二次被认为是更新操作。

使用:put ‘表名’,’列族名1:列名1’,’值’

 

5.3.2 get获取数据

功能:获取数据

使用:

获取指定rowkey的指定列族指定列的数据

 

获取指定rowkey的指定列族所有的数据

 

获取指定rowkey的所有数据

 

 

获取指定时间戳的数据

 

5.3.3 Count计算表的行数

功能:计算表的行数

使用:

 

5.3.4 put更新数据

详见5.3.1

5.3.5 scan全表扫描数据

功能:扫描全表所有数据

使用:

 

5.3.6 delete删除数据

功能:删除表中的数据

使用:

删除指定rowkey的指定列族的列名的数据

 

删除指定rowkey的指定列族的数据

 

5.3.7 deleteall删除整行数据

功能:删除整行数据

使用:

 

5.3.8 truncate删除全表数据

功能:删除表中所有的数据。正如你看到的,在HBase的help命令里并没有

使用:



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



如何对应用服务性能问题诊断(Tomcat、Weblogic中间件) - luihengk

$
0
0

在我们web项目中,我们常见的web应用服务器有Tomcat、Weblogic、WebSphere。它们是互联网应用系统的基础架构软件,也叫“中间件”,负责处理动态在页面请求,并为应用提供了名字、事务、安全、消息、数据访问等,此外,它们还是提供应该构建的开发、部署、运行及管理功能。

当我们对项目做性能测试时,我们如何更好地监控它们,并诊断出性能问题呢?下以是我对Tomcat和Weblogic的一些性能监控分析方法:

1、  Tomcat性能监控分析

Tomcat是一个免费的开放源代码的web应用服务器软件,主要用来支持运行Java Servlet/JSP。Tomcat运行时占用的系统资源小,扩展性好,支持负载平衡和邮件服务等开发应用系统常用的功能,而且它还不断的改进和完善中,使用Tomcat作为web应用服务器,在系统应用性能上有很大帮助,以下介绍几种监控Tomcat性能的方法:

1)  Tomcat自带的监控功能

使用过Tomcat的人大概都知道,它附带了一个监控页面,先修改配置文件/conf目录下的tomcat-users.xml文件,为监控的用户添加权限,并且需要添加一个名为“manager-gui”的角色,如下:

1 <role rolename="manager-gui"/>
2
3 <user username="monitor" password="123456" roles="manager-gui"/>
4

 

保存后,访问 http://localhost:8088/manager/status,如图,可查看Tomcat性能情况

 2)  用LambdaProbe监控Tomcat

网上下载probe压缩文件, http://www.lambdaprobe.org/解压后,可以看到有个probe.war文件,接着需要修改两个文件

a、修改tomcat下conf/ tomcat-users.xml文件,添加如下代码:

1 <role rolename="manager"/>
2 <role rolename="poweruser"/>
3 <role rolename="poweruserplus"/>
4 <role rolename="probeuser"/>
5 <user username="probe" password="123456" roles="manager,probeuser,poweruser,poweruserplus"/>
6

 b、修改tomcat下bin/Catalina.bat文件,添加如下代码:

set CATALINA_OPTS=-Xms512m -Xmx1024m -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=29001 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

 启动tomcat后,访问 http://localhost:8088, 输入用户名:probe,密码123456,登录后,

在页面中“ WAR file to deploy”点击“浏览”将probe.war文件发布到tomcat应用中

 访问 http://localhost:8088/probe/,查看tomcat实时运行的应用程序的性能,如图

 3)  LoadRunner编写脚本实现Tomcat性能监控

LR不支持直接监控Tomcat,但是可以在VUGen中编写脚本来获取性能数据,其实是编写大量的关联函数web_reg_sava_param()及lr_user_data_point函数,例如:

1 double atof(const char *string);
2
3 extern char * strtok(char * token, const char * delimiter);
4
5 collectMetrics(){
6
7 int countP, counts, countF, countF, countR, countK;
8
9 int numValues;
10
11 static int loggedVersionInfo = FALSE;
12
13 lr_save_string(“127.0.0.1”,”ServerName”);
14
15 web_set max_html_param_len(65565);
16
17 web_set_user(“admin”,”admin”,”{ServerName}”);
18
19 lr_start_transaction(“monitor tomcat”);
20
21 web_reg_save_param(“JVMFreeMemory”,”LR=Free memory”,”RB=MB”,”Ord=1”,LAST);
22
23 略……………这里添加多个监控指标
24
25 Lr_end_transaction(“monitor tomcat”,LR_AUTO);
26
27
28
29 写入Tomcat JVM度量数据
30
31 Lr_user_data_point(“Tomcat JVM Free memory”,atof(lr_eval_string(“{JVMFreeMemory}”)));
32
33 }
34

然后在Run-time中设置数据收集的间隔“pacing”,最好设置在5-10s,最后在Controller中设置脚本运行,场景运行完毕后,在Analysis分析结果图标中添加“User Defined Data Points”,查看收集到的Tomcat性能数据。

4)  JMX监控Tomcat

使用JMX监控Tomcat,需要编写JMX提供接口的实现类,该接口是任何java程序都可以调用访问的,编写java程序来收集Tomcat性能数据,在此就略过啦!

5)  优化JVM提高Tomcat性能

a、  修改Tomcat启动/最大时的运行内存来监控性能指标的影响,即修改bin/Catalina.bat文件;

JAVA_OPTS=-Xms512m -Xmx1024m

b、  修改conf目录下server.xml文件maxThreads的值来调整Tomcat的最大连接线程数;

c、  同上,修改connectionTimeout的值来调整连接超时数;

d、  同上,修改acceptCount的值来调整最大排队数;

 2、  Weblogic中间件监控性能分析

a、  在weblogic控制台页面调整Session策略;

b、  JDBC连接数监控及参数的调整,如Initial Capacity、Maximum Capcity等;

c、  JVM监控分析,可设置JVM启动时的参数;


本文链接: 如何对应用服务性能问题诊断(Tomcat、Weblogic中间件),转载请注明。

TCP连接的建立和终止

$
0
0

 

TCP数据包格式:


 
TCP数据包中没有标识数据大小的字段,这个字段定义在IP首部中了。

TCP首部长度最小是20字节,最大是60字节,首部长度就定了偏移量,标识了TCP首部的大小

TCP流量控制是由连接的每一端通过声明 窗口大小来提供的,这个值是16比特,所以最大是65535字节。

校验和覆盖了整个TCP报文段,首部和数据,这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证。

只有当URG标志设置为1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。

最常见的可选字段是  最长报文大小,又称为 MSS(Maximun Segment Size)。每个连接方通常都在通信的第一个报文段(SYN包)中指明这个选项,它指明本端所能接收的最大长度的报文段。

比如A的MTU为296字节,也就是以太网可以发送的包的最大大小,而B的MUT是1500字节,那么当双方建立连接时,A发送的SYN包就指明了MSS为256(296-40),而B的SYN包中指明了MSS为1460(1500-40)。此时使用较小一方的MSS,也就是256字节作为数据报文长度。

MSS默认值为536字节

 

 

TCP中的六个标识比特,他们中的多个可以同时被设置为1,含义如下

标志比特含义
CWR流量控制
ECN拥塞窗口
URG紧急指针有效
ACK确认序号有效
PSH

接收方应尽快将这个

报文段交给应用层

RST重建连接
SYN

同步序号用来发起一个

连接

FIN

发端完成发送任务

 

 

TCP的状态变迁图


 

 

 

TCP连接的建立,数据传输,以及关闭的过程


 
 

状态转换和连接建立关闭的对比图


 
分成三部分

1.连接的建立过程

2.数据的传输过程

3.连接的关闭过程

 

连接过程(三次握手)

这是由一个主动,一个被动的过程,客户端主动触发一个连接,服务端接收连接,最初客户端和服务端都处于 CLOSED状态。

对于客户端来说,首先会发送一个SYN包,之后TCP状态就变为 SYN_SENT,而当客户端收到服务端发来的ack+syn包时,对于客户端来说他已经确定了服务端收到了之前发送的SYN包了,所以客户端的TCP状态就变成了 ESTABLISHED.

对于服务端来说,当调用listen()函数之后,就看以监听客户端的发来的SYN包了,当收到SYN包之后,服务端的TCP状态就变为 TCP_RCVD,同时客户端还会向服务端发送一个syn+ack包,也就是服务端也要创建连接。最后当客户度收到这个syn+ack包后,最后会再发一个ack包给服务端,也就是TCP状态转换图中SYN-SEND状态指向 SYN-RECEVED状态的箭头,也就是客户度最后的确认ack,当服务端收到这个ack后,连接就建立了,这样服务端的TCP状态也变为 ESTABLISHED.

 

数据传输过程

只有一种状态 ESTABLISHED

 

关闭过程

这里分为主动关闭和被动关闭,还有双方同时关闭。

客户端发送fin包后,TCP状态就处于 FIN_WAIT_1,如果收到服务端发来的ack确认后,状态就变为 FIN_WAIT_2。之后客户端会等待服务端发送fin包,也就是等待服务端关闭。当收到服务端发来的fin包后,客户端会发送一个确认,此时客户端的状态就变为 TIME_WAIT,等待2ML时间后,状态就变为了 CLOSED

对于服务端来说,收到客户端发来的fin包后,状态就变为 CLOSE_WAIT,也就是被动关闭,同时会发送一个ack确认给客户端。之后服务端也会发送一个fin包给客户端,表示关闭连接,之后状态就变成了LAST_ACK,此时服务端会等客户端发送最后一个确认ack,当收到后服务端就会关闭连接,状态就变为 CLOSED

同时关闭是双方都是主动关闭,双方都发送了一个fin包。客户端主动关闭发送fin包后,变成 FIN_WAIT_1状态,此时又收到了一个fin包,于是状态变为 CLOSING,同时再发送一个确认包ack给对方。而当收到对方对fin包的确认后,状态变成了 TIME_WAIT,等待2ML时间后,连接关闭,变为 CLOSED状态,对于服务端来说情况是一样的就不在阐述了。

同时关闭的状态图


 
 

通过Wireshark抓包分析连接的建立和关闭过程

表达式为:

(ip.dst_host==61.135.169.105 and ip.src_host==192.168.0.100) or (ip.dst_host==192.168.0.100 and ip.src_host==61.135.169.105)


 

详细看一下连接的建立过程,首先是客户端发送一个SYN包

此时的只有一个序列号,没有确认序列号,序列号是3285497608

另外在可选项中有一个MSS,设置为1460,还有一个SACK。

 

服务端收到SYN包后,发送SYN+ACK包

此时服务端的序列号是3447498448,同时对客户端的序列号进行了确认,也就是序列号+1,所以ack是3285497609

服务端的MSS设置为1440,所以使用两者中较小的一个MSS,也就是1440字节。

 

最后客户端回一个ack包给服务端

应答的ack是服务端序列号+1,所以ACK就是3447498449

 

双方关闭连接的四次握手TCP包都没有数据,包头都是20字节,通过Wireshark的抓图就能看出来,这里就不再描述了。 

 

 

参考:

TCP的那些事儿

TCP协议中Window Scale Option问题

TCP/IP ECN分析

Congestion window

TCP协议

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



怎样读书比较快?

$
0
0

我经常被人问这样的问题:“你读书似乎很快,有什么经验介绍吗?”。刚开始面对这样的问题,总是觉得莫名其妙,因为我从来也没觉得自己读书有多快。直到慢慢被问得多了,我逐渐意识到,大概有人觉得自己读书速度不如我快,所以希望讨教一些秘诀。可是仔细想想,我确实没有掌握什么妙方。如果真的要分析我为什么读书“比较快”的话,我能列出来的只有自己的若干经验。

关于阅读,我印象最深的一件事是自己刚工作的时候。项目经理让我去学习一门新技术,我找了本英文教材,他说“没问题,下周你来给大家讲解吧。”当时我感觉这完全是不可能的任务。虽然在学校也读过一些英文书,但速度大概是每个学期3到4本,偶尔能看5本以上,就觉得相当有成就感了。现在要求一周内看完一本英文教材,还得给同事讲解,这是我从来没想过也没经历过的。但是公司与学校不一样的地方就在于,在学校还有补考,在公司只会被开。结果我真的花一周的业余时间看完了这本书,第二周给大家讲解的效果竟然还不错。从此,我就把读这类书的时间预期缩短到一周以内,我惊奇地发现,这个预期很多情况下确实可以做到,而且获益良多。这件事给我的印象太深刻了,平时大家总说“潜力”,但似乎都关注的是工作和学习的潜力,却没有想过阅读也是有潜力的。很多人抱怨自己读书不够快,似乎是觉得自己没有阅读的天赋,其实真正的原因是,自己没有认识到自己的阅读潜力,而大多数人的潜力其实是相当大的。所以,如果你对自己的阅读速度不满意,不妨给自己来点压力,确定自己是否达到了自己的阅读能力界限。

关于阅读,还有一本我印象深刻的书,叫做 《怎样阅读一本书》。因为之前我总认为阅读应该是人类与生俱来的能力,拿起书本来一页页看,这就叫“阅读”了。有人读得快,是因为他们看得简单,或者大脑比较好,能够做到一目十行。《怎样阅读一本书》让我真正深刻意识到,阅读原来是讲方法的,比如什么书应该精读,什么书应该略读,一本书的哪些部分应该精读,哪些部分应该略读…… 我之前一直不理解发达国家的大学生怎么能完成那么繁重的阅读任务,因为按照我的估算,就算一目十行,每天不休息,也很难在规定的时间里读完那么多书。后来我才明白,我们常常把“阅读”理解为“精读”了,而列出的书单里,并不是每一本都需要完整精读的,很多书只需要精读其中一部分甚至略读就可以了。遗憾的是,我们的教育里从小就缺乏这样的内容,即便大学英语里有了“精读”和“略读”的区分,很多人却根本不了解意义,直接简化为“精读要考试略读不要考试”,真是非常可惜。不掌握阅读的方法论,即便天赋异禀,可以一目十行,甚至一目二十行,其实都不算快,更不要说阅读质量了。

既然谈到了“阅读质量”,不妨多说两句。因为大家讨论读书速度的目的,多半不是为了尽快地在豆瓣读书上标记自己读过的书,还是希望从中获得更多收获,所以如果只有速度而没有质量,再快都没有意义。根据我的经验,既能保证阅读质量又能提高阅读速度的办法之一,就是阅读之后的讨论。在大学期间,我曾在一个礼拜内读完了王晓明的 《无法直面的人生:鲁迅传》,之后怀着澎湃的心情去与 中文系的王老师讨论。他问“你看的谁写的鲁迅传?”,我说“王晓明”,他说“噢,这本书我知道,王晓明的书语言比较诗化,很有感染力。不过,你也要注意……,如果你有兴趣了解鲁迅,还可以去阅读这些书……”。在那电光火石的瞬间,我忽然意识到,如果没有听到他的评价,我固然读完了书,固然记住了很多,固然激动,其实还是懵懂地在这本书所营造的世界里游荡,没能跳出来看看问题的全貌。我也从此意识到,讨论对阅读来说是多么的重要。

在学习技术知识时,讨论可能并不重要,因为书里的内容可以由客观标准来验证(对计算机来说更是如此)。但是对其它种类的知识,尤其是稍微艰深、复杂的知识,讨论是真正掌握的必经之路。否则,无论你看了多少书,理解都未必准确。这样的例子我见过不少,经验丰富的老翻译家会用物理学的新进展来论证自己的翻译理论,理工科出身的知名写手乱借用人文社科的理论而浑然不知,在我看来同样可惜——不能说他们的天份不高,也不能说他们刻意要拉大旗作虎皮,但我猜他们学习这些知识时都没有经过专门的讨论,所以谈不上真正掌握。如果你身边找不到这样可以讨论的人,至少可以从网上找相关的书评和讨论,比对、修正、完善自己的理解。我经常遇到有朋友在豆瓣读书我写的书评下留言,或者发豆邮,这种态度我非常欣赏。退一步说,哪怕非专业的书籍,与人讨论也能让自己的收获倍增——我尝试和我家LD分头看同一本书,再集中讨论,觉得收获很大,不但加深了自己的理解,也填补了自己阅读时的很多空白。

如果实在是找不到同好来讨论自己阅读的内容,还有一个加深理解的好办法,就是写读后感。读一本书或者非常容易,但是要写读后感,哪怕只是短短几百字的读后感,也会非常让人头疼。你会逼迫自己把读过的内容翻过来倒过去,仔细思考,梳理出自己认可的逻辑,并按照一定的结构组织起来。我在阅读哈耶克的 《自由秩序原理》时,身边没有找到有共同兴趣的同好,也找不到太多合适的学习材料,于是我只能每读一章就写出这章的读后感。这样虽然读得很慢很累,但我确信自己读懂了这本书,深刻理解了自由对人类文明的重要意义,后来与其他人的讨论也证明了这一点。

最后我想说的是,阅读速度不是孤立阅读一本书的速度,而是所有你的阅读量的加速度。因为之前的知识积累,在很大程度上影响着你阅读当前这本书的速度。举个例子,你先读了一本中国历史,大致知道了从秦到清的历史;然后又阅读了一本世界历史,知道除了中国历史之外,世界上的其它地方还发生了哪些事情;然后你再读到关于人类发展的书,你就可以把之前自己关于中国和世界历史的知识利用起来,知道什么年代中国发生了什么事情,世界上其它地方发生了什么事情,这样构建出一张有机的图谱,不必反复阅读、刻意记忆,就能自然而然地联想、理解很多;再然后,你遇到其它历史类书籍,就可以把它和自己内心的图谱相对照,判断这本书的各个部分说得对不对,对的地方认真阅读,不对的地方可以略读,或者你干脆判断这本书没什么价值,可以直接略过……如此继续下去,你的阅读速度只会越来越快,知识也越来越牢固。同时,你也不必担心“越读越狭隘”,因为高质量的知识多半是能够彼此兼容的,至少不会彼此尖锐对立。只要你抱定开放的心态,必然可以不断提高自己的阅读鉴别力,通过除莠存良,提高自己的阅读效率。


法国费加罗报头版刊登的中国游客照片令法国人震撼

线程的生命周期 - 理解Java中线程的状态

$
0
0

    如果你在工作中需要使用到线程,或是需要在多线程环境下编程,那么了解 线程的生命周期(Life Cycle of Thread)以及 线程的状态(Thread States)是很有必要的。

    正如我们在上一篇文章中了解到的,通过实现Runnable接口或是继承Thread类,我们可以创建一个 Java线程类。如果想要启动线程,我们需要创建一个线程类,然后调用它的start()方法来执行run()中的任务,这样就能将其线程来运行。

线程的状态

    下图展示了Java中线程的不同状态,需要注意的是,虽然我们创建并启动了线程,但是线程在就绪、运行、阻塞状态间切换则是由操作系统的线程调度器来实现的,Java对此实际上并没有完全控制权。


新建(New)

    我们使用new操作符来创建新的线程对象,线程的状态是“新建”。此时,线程并不是活跃的,它只是Java程序的一个内部状态。

就绪(Runnable)

    当我们调用线程对象的start()方法时,线程的状态切换为“就绪”,而线程的控制权就交给了线程调度器,直至线程结束运行为止。操作系统的线程调度器决定立即启动线程,或是暂时先把它放在就绪线程队列中。

运行(Running)

    当线程开始执行时,它的状态切换为“运行”。线程调度器从就绪队列中选出一个线程,并将它的状态改为“运行”,然后CPU开始执行该线程。如果当前时间片结束,线程会被切换到就绪状态。run()方法执行结束,线程进入死亡状态。而如果线程需要等待某些资源,它则会进入阻塞状态。

阻塞/等待(Blocked/Waiting)

    可以使用 join方法可以让线程进入等待状态直至另一个线程结束运行。或是当线程需要访问某些资源时,例如 生产者消费者问题服务员通知或是IO资源,它也会进入等待状态。一旦线程结束等待,它就进入就绪状态,并被移回就绪线程队列中。

死亡(Dead)

    一旦线程执行结束,它就会进入死亡状态,此时的线程被视为失去活力。

    以上就是线程的不同状态,了解它们并理解如何进行线程状态切换,对你是很有帮助的。


原文地址: Life Cycle of Thread - Understanding Thread States in Java



作者:snarlfuture 发表于2014-6-2 1:38:01 原文链接
阅读:0 评论:0 查看评论

车牌识别--模板库C语言数组的制作

$
0
0

在车牌识别中,字符模板匹配的模板库是很大的。

包括 10个阿拉伯数字以及26个英文字母还有几十个汉字,每个库都是一张小图片,加载起来也比较繁琐。

后面还有可能为提高识别增加额外的模板库。

之前的处理中,是把这些库的图片文件放到一个文件夹中,程序启动后,再一个一个读取,这样文件的数量就比较多。

原图片模板如下:


程序稳定后,我们就不要这些字符模板库了,可以用数组的形式代替,就是把这些文件数据保存一个c语言数组里面,直接编译到程序中,运行程序的时候直接使用,不用一个一个加载,再去匹配。

目前使用的moan库图片是20x40的8bit灰度BMP格式文件,其信息头长度54+256x4=1078,直接略过信息头和调色板获取图片数据信息

模板制作的c代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define CHAR_NUM 66
#define CHAR_WIDHT 20
#define CHAR_HEIGHT 40

char template[CHAR_NUM][CHAR_WIDHT * CHAR_HEIGHT];

int readstr(FILE *inFIL, unsigned char *srcBmp)
{

	int width,height, headlength;
	int i,j,line8;
	unsigned char *temp;
	unsigned char temp1;

	width = CHAR_WIDHT;
	height = CHAR_HEIGHT;
	headlength = 1078;//54 + 256 * 4; 

	line8=(width*8+31)/32*4;

	temp=(char *)malloc(height * line8 * sizeof(char));
	
	fseek(inFIL, headlength, SEEK_SET);
	
	fread(temp, line8 * height,1, inFIL);
	
	if(temp==NULL)
	{
		printf("\n读取失败\n"); 
		return -1;
	}

	for(i=0;i<height;i++)
	{
		for(j=0;j<width;j++)
		{
			temp1 = temp[i*line8+j];
			if(temp1 > 150)
				temp1 = 255;
			else
				temp1 = 0;
			srcBmp[(height-i-1)*width+j]= temp1;// (temp1 > 150 ? 255:0);//(byte)(0.299*bitmap[temp[i*line8+j]].bitb+0.578*bitmap[temp[i*line8+j]].bitg+0.114*bitmap[temp[i*line8+j]].bitr);
		}
	}
	free(temp);
	temp=NULL;
	return 0;
}

int readtemplate(char *path, char src[CHAR_NUM][CHAR_WIDHT * CHAR_HEIGHT])
{
	FILE *f[72];
	int i;
	char str[100];

	for(i = 0; i <= CHAR_NUM; i++)
	{
		sprintf(str, "%s%d.bmp", path, i);
		f[i]=fopen(str,"rb");
		if(f[i]==NULL)
		{
			printf("can't open patch:%s\n", str);
			return -1;
		}
		readstr(f[i], src[i]);
		fclose(f[i]);
	}
	return 0;
}


int main()
{
	int i, j;
	FILE *f;
	unsigned char p;
	char buf[5];
	f = fopen("Template.h", "wb");
	if(f == NULL)
	{
		printf("Can't open the file\n");
		return -1;
	}
	if(readtemplate(".\\test\\moban\\", template) != 0)
	{
		printf("readtemplate error\n");
		return -1;
	}
	for(i = 0; i < CHAR_NUM; i++)
		for(j = 0; j < CHAR_WIDHT * CHAR_HEIGHT; j ++)
		{
			if((j%800 == 0))
			fwrite("\n",strlen("\n"),1,f);
			p = template[i][j];
			sprintf(buf,"%4d,", p);
			fwrite(buf,strlen(buf),1,f);
		}

	fclose(f);
	return 0;
}

制作后的数组如下(变量名自行添加)




之前算法是一个一个读取,然后重新复制一遍

void readmoban(char *path,struct BMP_Plate *img2)
{
	FILE *f[72];
	int i;
	char str[80];
	for(i=0;i<=66;i++)
	{
		sprintf(str,"%s%d.bmp", path, i);
		f[i]=fopen(str,"rb");	
		if(f[i]==NULL)
		{
			printf("can't open moban:%d,%s\n", i, str);
			exit(-1);
		}
		readstr(f[i],img2->strc[i]); 
		displayGray(img2->strc[i],20,40,0,0);
		fclose(f[i]);
	}
}

现在,只需要,指定数组指针,不用加载图片,也不用复制

int readtemplate(char *moban,struct BMP_Plate *img2)
{

	int i;
#if 0	
	for(i = 0; i <= CHAR_NUM; i++)
	{
		memcpy(img2->strc[i],&moban[i * TEMPPLATE_SIZE], TEMPPLATE_SIZE);
	}
#else
	for(i = 0; i <= CHAR_NUM; i++)
	{
		img2->strc[i] = &moban[i * TEMPPLATE_SIZE];
	}
#endif
	return 0;
}
不用再重新复制数据了,优化了代码,节省了时间(其实节省的也不是很多^^ )。
作者:liujia2100 发表于2014-6-1 23:10:17 原文链接
阅读:91 评论:0 查看评论

nginx源码分析--GDB调试

$
0
0
利用gdb[i]调试nginx[ii]和利用gdb调试其它程序没有两样,不过nginx可以是daemon程序,也可以以多进程运行,因此利用gdb调试和平常会有些许不一样。当然,我们可以选择将nginx设置为非daemon模式并以单进程运行,而这需做如下设置即可:
daemon off;
master_process off;

这是第一种情况:
这种设置下的nginx在gdb下调试很普通,过程可以[iii]是这样:
执行命令:
lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb ./nginx
当前目录是在/usr/local/nginx/sbin,该目录下有执行程序nginx,上条命令也就是用gdb来开始调试nginx,进入gdb命令行,直接输入r即可执行nginx:
(gdb) r
Starting program: /usr/local/nginx/sbin/nginx
src/core/ngx_conf_file.c 1163 : 1000000
===============================
ngx_timer_resolution 1000000
因为nginx以前台形式运行,键盘输入被nginx接管,此时无法输入gdb命令,因此需要按Ctrl+C退到gdb命令行模式,而nginx被中断暂停在__kernel_vsyscall调用里,输入bt命令可以查看到调用堆栈信息:
(gdb) r
Starting program: /usr/local/nginx/sbin/nginx
src/core/ngx_conf_file.c 1163 : 1000000
===============================
ngx_timer_resolution 1000000
^C
Program received signal SIGINT, Interrupt.
0xb7f29430 in __kernel_vsyscall ()
(gdb) bt
#0  0xb7f29430 in __kernel_vsyscall ()
#1  0xb7e081a8 in epoll_wait () from /lib/tls/i686/cmov/libc.so.6
#2  0x08073ea3 in ngx_epoll_process_events (cycle=0x860ad60, timer=4294967295,
flags=0) at src/event/modules/ngx_epoll_module.c:405
#3  0x080668ee in ngx_process_events_and_timers (cycle=0x860ad60)
at src/event/ngx_event.c:253
#4  0×08071618 in ngx_single_process_cycle (cycle=0x860ad60)
at src/os/unix/ngx_process_cycle.c:283
#5  0x0804a926 in main (argc=1, argv=0xbfd2ae44) at src/core/nginx.c:372
(gdb)
好,来给nginx设置断点,这很简单,比如这里给函数ngx_process_events_and_timers设置个断点,再输入命令c继续执行nginx:
#4  0×08071618 in ngx_single_process_cycle (cycle=0x860ad60)
at src/os/unix/ngx_process_cycle.c:283
#5  0x0804a926 in main (argc=1, argv=0xbfd2ae44) at src/core/nginx.c:372
(gdb) b ngx_process_events_and_timers
Breakpoint 1 at 0x80667d6: file src/event/ngx_event.c, line 200.
(gdb) c
Continuing.
Breakpoint 1, ngx_process_events_and_timers (cycle=0x860ad60)
at src/event/ngx_event.c:200
200  {
(gdb)
结果我这里gdb马上提示断点中断,这是因为恰好调到这个函数而已,也许在你那并不会马上中断,从而gdb就一直停在Continuing后面,此时我们就要主动去触发事件(或者等待,时间可能很久,根据你的nginx设置)使得nginx调用这个函数,比如利用浏览器去访问nginx监听的站点,使得nginx有事件发生。
断点中断后,利用s、c等gdb常规命令进行我们的调试,跟踪,这些无需多说:
200  {
(gdb) s
__cyg_profile_func_enter (this=0x80667d0, call=0×8071618)
at src/core/my_debug.c:65
warning: Source file is more recent than executable.
65      my_debug_print(“Enter\n%p\n%p\n”, call, this);
(gdb)
66    }
(gdb) c
Continuing.
ngx_timer_resolution 1000000
第二种情况:
当以daemon模式(即配置选项:daemon on;)单进程运行nginx时,上面那种方法不凑效了,原因很简单,当nginx以daemon模式运行时,这个启动过程中nginx将fork好几次,而那些父进程都早已直接退出了,因此看到的会这样:
lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb ./nginx
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type “show copying”
and “show warranty” for details.
This GDB was configured as “i486-linux-gnu”…
(gdb) r
Starting program: /usr/local/nginx/sbin/nginx
src/core/ngx_conf_file.c 1163 : 1000000
===============================
Program exited normally.
(gdb)
而事实上nginx并没有退出,退出的是其父(或祖父)进程,而gdb没有跟着fork跟踪下去:
lenky@lenky-desktop:/usr/local/nginx/sbin$ pidof nginx
7908
gdb考虑了这种情况,因此也提供了相应的follow-fork-mode选项:
其用法为:
set follow-fork-mode [parent|child]
说明:
parent: fork之后继续调试父进程,子进程不受影响。
child: fork之后调试子进程,父进程不受影响。
设置了该选项后,其它调式操作和之前介绍的基本一样,相关示例如下:
lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb ./nginx -q
(gdb) r
Starting program: /usr/local/nginx/sbin/nginx
src/core/ngx_conf_file.c 1163 : 1000000
===============================
Program exited normally.
(gdb) shell pidof nginx
9723
(gdb) shell kill -9 9723
(gdb) set follow-fork-mode child
(gdb) b ngx_process_events_and_timers
Breakpoint 1 at 0x80667d6: file src/event/ngx_event.c, line 200.
(gdb) r
Starting program: /usr/local/nginx/sbin/nginx
src/core/ngx_conf_file.c 1163 : 1000000
===============================
[Switching to process 9739]
Breakpoint 1, ngx_process_events_and_timers (cycle=0x8ff0d60)
at src/event/ngx_event.c:200
200  {
(gdb) s
[tcsetpgrp failed in terminal_inferior: No such process]
__cyg_profile_func_enter (this=0x80667d0, call=0×8071618)
at src/core/my_debug.c:65
warning: Source file is more recent than executable.
65      my_debug_print(“Enter\n%p\n%p\n”, call, this);
(gdb) c
Continuing.
上面我们先设置断点,这样执行r命令后nginx将自动被中断返回到gdb命令行,如果不这样做,那么将无法返回gdb命令行,即按Ctrl+C没有效果,因为nginx是以daemon模式运行的,输入输出已经被重定向,nginx没有接收到这个Ctrl+C输入。当然也并不是没有其它办法,比如另外一个shell窗口,利用kill命令给nginx进程发送一个SIGINT信号即可,这和按Ctrl+C是一样的,如下(假定9897为nginx进程id号):
lenky@lenky-desktop:~$ sudo kill -2 9897
第二种情况:
第三种情况就是不管nginx运行模式了,是通用的,即利用gdb的attach、detach命令。
假定当前nginx的相关配置这样:
daemon on;
master_process on;
worker_processes  1;
即daemon模式,多进程运行nginx。
lenky@lenky-desktop:/usr/local/nginx/sbin$ sudo gdb -q
(gdb) shell ./nginx
src/core/ngx_conf_file.c 1163 : 1000000
===============================
(gdb) shell pidof nginx
10246 10245
(gdb)
可以看到一共有两个nginx进程,这里10245为master进程,而10246为worker进程。我们要调试worker 10246可以如下:
(gdb) attach 10246
Attaching to program: /usr/local/nginx/sbin/nginx, process 10246
Reading symbols from /lib/tls/i686/cmov/libcrypt.so.1…done.
Loaded symbols for /lib/tls/i686/cmov/libcrypt.so.1
Reading symbols from /lib/libpcre.so.3…done.
Loaded symbols for /lib/libpcre.so.3
Reading symbols from /usr/lib/libz.so.1…done.
Loaded symbols for /usr/lib/libz.so.1
Reading symbols from /lib/tls/i686/cmov/libc.so.6…done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2…done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /lib/tls/i686/cmov/libnss_compat.so.2…done.
Loaded symbols for /lib/tls/i686/cmov/libnss_compat.so.2
Reading symbols from /lib/tls/i686/cmov/libnsl.so.1…done.
Loaded symbols for /lib/tls/i686/cmov/libnsl.so.1
Reading symbols from /lib/tls/i686/cmov/libnss_nis.so.2…done.
Loaded symbols for /lib/tls/i686/cmov/libnss_nis.so.2
Reading symbols from /lib/tls/i686/cmov/libnss_files.so.2…done.
Loaded symbols for /lib/tls/i686/cmov/libnss_files.so.2
0xb8016430 in __kernel_vsyscall ()
(gdb) b ngx_process_events_and_timers
Breakpoint 3 at 0x80667d6: file src/event/ngx_event.c, line 200.
(gdb) c
Continuing.
Breakpoint 3, ngx_process_events_and_timers (cycle=0x8f43d68) at src/event/ngx_event.c:200
200  {
(gdb) detach
Detaching from program: /usr/local/nginx/sbin/nginx, process 10246
(gdb)
总的来看,还是第三种方法最顺手了。



[i] http://www.gnu.org/software/gdb/
[ii] nginx是打开了-g选项编译的。
[iii] 意思是说下面的方法只是众多方法之一。
作者:yusiguyuan 发表于2014-6-1 22:33:12 原文链接
阅读:101 评论:0 查看评论

tomcat集群配置

$
0
0

所使用到的软件:

Apache 2.2.17

tomcat 6.0.29

mod_jk.so

OS环境:windows XP 32位

服务器集群会比单机的TPS提高不少,也提高了系统的可用性,避免单机宕机影响整个系统不能运行,所以集群会比单机有众多优点。

Apache的安装过程略。

mod_jk.so使用的是tomcat-connectors-1.2.39-windows-i386-httpd-2.2.x版本,从名字可知,这个tomcat的connectors会对应多个Apache 2.2不同的版本。

首先, 把mod_jk.so放到Apache的modules目录下。

Apache的配置:

httpd.conf的配置:

把下面模块的注释*号去掉,加载这些模块

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so

 配置虚拟主机,把下面这行前面的#去掉

Include conf/extra/httpd-vhosts.conf

 在文件的最后面追加

#load balance config
ProxyRequests Off   <proxy balancer://cluster>   
  BalancerMember ajp://127.0.0.1:8009 loadfactor=1 route=jvm1
  BalancerMember ajp://127.0.0.1:9009 loadfactor=1 route=jvm2 </proxy>

 这是AJP方式的集群配置。 loadfactor是负载因子,如果都是1分发请求时就是1:1的分发,如果1个是2,1个是1,分发时的比例就是2:1。route=jvm1中的jvm1指的是tomcat的server.xml中配置的Engine节点的jvmRoute属性。

httpd-vhosts.conf的配置

<VirtualHost *:80>   
      ServerAdmin localhost
      ServerName localhost
      ServerAlias localhost   
      ProxyPass / balancer://cluster/ stickysession=jsessionid nofailover=On   
      ProxyPassReverse / balancer://cluster/
      ErrorLog "logs/lbtest-error.log"  
     CustomLog "logs/lbtest-access.log" common  </VirtualHost>

 tomcat的配置:

本例使用了两个tomcat实例,分别为t1和t2。

t1的server.xml配置,把下面这行语句的注释去掉

<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">

 这里的jvmRoute的值即是apache的httpd.conf最后一段的route的对应值。

启用集群,把下面这句的注释去掉

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

 t2的server.xml的配置,除了上面的共性配置外,还因为是在一台机器上运行的两个tomcat,为了避免和t1的冲突,还需要修改三个地方的端口号:

SHUTDOWN、Connector和AJP的port 值不能和t1的相同,否则会有冲突。

如果使用session同步,需要在context.xml中设置一下

<Context distributable="true">

测试页面test.jsp

<%@ page contentType="text/html; charset=UTF-8" %> <%@ page import="java.util.*" %> <html><head><title>Cluster App Test</title></head> <body> 
Server Info:  <%  
out.println(request.getRemoteAddr() + " : " + request.getLocalPort()+"<br>");%> <%  
      out.println("<br> ID " + session.getId()+"<br>");   
      String dataName = request.getParameter("dataName");  
      int i = 0;
      if(session.getAttribute("val")!=null){
         i = Integer.parseInt(session.getAttribute("val").toString());
      }
 	  session.setAttribute("val", ++i);
      out.println("<br> value i: " + session.getAttribute("val")+"<br>");   
     if (dataName != null && dataName.length() > 0) {  
        String dataValue = request.getParameter("dataValue");  
        session.setAttribute(dataName, dataValue);  
     }
  %> </body> </html>

 Apache和t1、t2启动后,可以看到请求会分发到两个tomcat中,session也实现了复制共享。

 访问http://localhost/test/test.jsp,刷新页面会发现,session实现了复制共享。
 

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Google程序员主要由白人和亚裔组成

$
0
0
Google公布了员工构成比例数据,显示其程序员主要是白人和亚裔组成。Google全球46170位员工中,有30%是女性,技术人员中有17%是女性。在美国雇员中,61%是白人,约三分之一是亚裔(远高于全美平均值);技术人员中,60%是白人,亚裔占到34%。Google的女性比例其实已经够高了,亚马逊四分之三的雇员是男性。目前围绕科技行业多元化缺失问题的辩论越来越激烈。尽管科技行业是经济增长的重要驱动力,但从性别、年龄或种族来看,该行业的员工构成状况远远没有反映出美国的人口构成。在工程师、创始人和董事会成员等岗位上也同样存在这种失衡问题。






JVM是如何分配和回收内存?有实例! - zhanjindong

$
0
0

上一篇博客我简单介绍了下如何手动计算一个Java对象到底占用多少内存?今天就想聊下这个内存JVM到底是是如何分配和回收的。

Java整体来说还是一个GC比较友好的语言,无论是分代的垃圾收集,还是基于GC Roots的可达性算法都是业界普遍的经典做法,关于Java的内存区域划分以及GC的一些基本知识,我这里就不赘述了,可以看我之前的博客: http://zhanjindong.info/category/note/dsbj/

《深入理解Java虚拟机第2版》这本书非常值得一看,最近几篇读博客都算这本书的读书笔记吧。本人文笔很烂,所以都是记流水账枯燥乏味的文章。进入正文之前还是要交代下环境:以下内容都是基于HotSpot虚拟机Server模式,垃圾收集器用的是默认的Serial和Serial Old。

 

JVM内存分配和回收策略

话说一图胜千言,本也打算画张活动图就了事了:

但是画完发现:一画图更麻烦,太大了看的累(想看的可以在新建窗口放大了看),其次感觉还是说不清楚(画的不对的地方欢迎批评),最后觉得还是文字描述一下整个流程:

1、当JVM给一个对象分配内存的时候, 如果启动了本地线程分配缓存,将按线程优先在TLAB上分片,TLAB只是起缓存作用减少高并发下CAS带来的性能损失,跟GC的分代没有冲突。

2、当分配一个对象的时候会优先在Eden区域分配,如果Eden有足够的空间,那么内存分配很顺利的结束,不会触发任何GC操作;

3、当Eden区域空间不足的时候,会尝试着进行一次Minor GC,之所以说尝试是因为在进行Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象空间总和,如果是的那么可以保证这次Minor GC顺利进行;否则,虚拟机会检查HandlePromotionFailure这个参数是否设置为允许担保失败,如果允许那么虚拟机会根据经验值(这个经验值是历次晋升到老年代对象的平均大小)来决定是否尝试这次GC,如果小于或者JVM觉得不能冒险,那么会进行一次Full GC;

4、Minor GC时会采用复制算法将所有存活的对象复制到Survivor空间中(既包括Eden区域存活的对象,也包括另外一个Survivor存活下来的对象),如果这时发现Survivor空间不足,那么这些存活对象会直接进入老年代,这就是“空间分配”担保,前面说到冒险,是因为老年代的空间仍有可能不够,这时还是要进行一次Full GC,但是除了极端情况,大部分时候通过担保还是能有效避免频繁的Full GC的,如果Full GC后仍然没有足够空间,那只能抛出OutOfMemoryError;

5、对象在Eden空间出生,经过第一次Minor GC后能够顺利的被转移到Survivor的话,那么它的GC年龄就变成1,以后每在Survivor中熬过一次Minor GC,年龄就增加1,直到超过一定程度(-XX:MaxTenuringThreshold,默认15岁)则晋升到老年代;

6、规则是死的,人是活的,虚拟机开发人员还想到了一个“动态对象年龄判定”算法:如果Survivor区域中相同年龄所有对象大小总和超过Survivor空间的一半,年龄大于等于该年龄的对象就可以直接进去老年代;

7、对象也可以直接分配在老年代,这主要是针对那些大对象,因为大对象的内存分配代价比较大(需要连续的内存空间),所以JVM提供了-XX:PretenureSizeThreshold这个参数。

 

为什么有两块survivor区域

我一开始很纳闷HotSpot虚拟机为什么要搞出两个Survivor区域内,只用一块有何不妥吗?最后在Stack Overflow找到一个答案:

http://stackoverflow.com/questions/10695298/java-gc-why-two-survivor-regions 按照里面的说法是为了减少虚拟机对内存碎片的处理,我想了半天我的理解是:

因为survivor中的对象在达到“老年”(-XX:MaxTenuringThreshold)之前肯定有对象已经变成“垃圾”了,这时候必须要对其进行回收,如果只使用一个survivor的话,那么要不容忍survivor存在内存碎片,要么要对其进行内存整理,出于和对Eden区域同样的考虑,所以实际上对Survivor的GC也是基于复制算法的,不过是从一个Survivor到另外一个Survivor(这也是GC日志中为什么叫from space和to space),所以Survivor的两个区是对称的,没有先后关系,所以Survivor区中可能同时存在从Eden复制过来对象,以及从前一个Survivor复制过来的对象,某一次GC结束时肯定会有一个Survivor是空的。

 

实例说明

以上都是理论,下面结合一小段代码简单演示下上面的内容,这段代码引自《深入理解Java虚拟机第2版》3.6.3节,我简单展开说明下。为了方便解释,我先把设置的虚拟机参数贴出来:

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:+UseSerialGC -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=5242880
  • -XX:+UseSerialGC这里使用默认的Serial GC进行说明;
  • -verbose:gc是为了打印出GC日志;
  • -Xms初始Java堆为20M;
  • -Xmx20M JVM最大使用的堆为20M不可扩展;
  • -Xmn10M,新生代的内存空间为10M;
  • -XX:SurvivorRatio=8 Eden与两个Survivor的比例是8:1:1;
  • XX:PretenureSizeThreshold直接在老年代区域分配对象的阈值为5M,其实可以不设置,这里为了明确变量。

测试代码如下:

我们一步步来看,首先只执行48,49两行:

allocation1 = new byte[_1MB / 2];
allocation2 = new byte[6 * _1MB];

通过GC日志发现没有发生任何GC,Eden区域够用(注意:关于一个Java对象导致占用多大内存,参看 我前一篇博客。),接着执行51,52两行:

allocation2 = null;
allocation3 = new byte[2 * _1MB];

可以看到了引发了一次GC,这是一次Minor GC,同时可以看到使用的垃圾收集器是默认的( Def,关于GC日志的理解,可以参看《深入理解Java虚拟机第2版》一书)。引发GC的原因是Eden已经没有足够的内存容纳allocation3对象,发生GC之后allocation2对象占用的内存空间被回收了,而allocation1“幸存”下来被转移到了from survivor区域。

接下来我们再执行57,58,59三行代码:

allocation4 = new byte[4 * _1MB];
allocation3 = allocation4 = null;
allocation5 = new byte[2 * _1MB];

第59行代码引发了第二次GC,仍然是一次Minor GC,可以看到allocation3和allocation4都被回收了,allocation5被顺利的分配到了Eden空间,但是为什么from space变成了0%而老年代区域却变成了6%,这6%应该是allocation1占用的,但是为什么跑到老年代了呢?显然它的“年龄”还没有到15岁啊。

 

啊哈!还记得吗JVM很聪明,它会“动态对象年龄判定”,从上一张图可以看到,Survivor区域已经使用超过了50%(67%),而且显然是同一年龄的对象(就一个对象嘛),所以在第二次GC的时候它晋升到了老年代,大家可以把allocation1对象分配为256kb再试试。

Ok,到目前为止都是Minor GC,想Stop-The-World很简单,我们直接分配一个很大的对象试试:

allocation6 = new byte[20*_1MB];

不仅Full GC了,而且内存溢出了,因为我们设置了-Xmx20M。同时可以看到JVM被逼急了在不同区域进行了GC,首先在新生代(Eden+Survivor0)将内存全部回收,导致对象晋升到老年代,其次在老年代和“永久代(HotSpot)”也都进行了GC,但是一点收获都没有,最后只能OOM。关于JVM的一些其他规则,比如大对象的分配,以及其他虚拟机的分配策略,就留给有兴趣的同学自己试试了。

 

今天就写到这,最后祝大家“六一快乐”……靠,看了下时间已经不是6.1,童年已经过去了!

PS:文章同步发布在我的个人博客 http://zhanjindong.info/2014/06/02/jvm-memory-and-gc/

 

 


本文链接: JVM是如何分配和回收内存?有实例!,转载请注明。


深入解析spring中用到的九种设计模式

$
0
0

转载请注明出处,文章首发于http://www.itxxz.com/a/javashili/tuozhan/2014/0601/7.html

 

设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。


今天,螃蟹在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设计的思想理念,才能在工作学习中运用到“无形”。


Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行内典范。好了,话不多说,开始今天的内容。


spring中常用的设计模式达到九种,我们举例说明:


第一种:简单工厂

又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。 
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。 
spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。如下配置,就是在 HelloItxxz 类中创建一个 itxxzBean。

<beans>
    <bean id="singletonBean" class="com.itxxz.HelloItxxz">
        <constructor-arg>
            <value>Hello! 这是singletonBean!value>
        </constructor-arg>
   </ bean>
 
    <bean id="itxxzBean" class="com.itxxz.HelloItxxz"
        singleton="false">
        <constructor-arg>
            <value>Hello! 这是itxxzBean! value>
        </constructor-arg>
    </bean>
 
</beans>


第二种:工厂方法(Factory Method

通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。
一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。
螃蟹就以工厂方法中的静态方法为例讲解一下:
import java.util.Random;
public class StaticFactoryBean {
      public static Integer createRandom() {
           return new Integer(new Random().nextInt());
       }
}
建一个config.xm配置文件,将其纳入Spring容器来管理,需要通过factory-method指定静态方法名称
<bean id="random"
class="example.chapter3.StaticFactoryBean" factory-method="createRandom" //createRandom方法必须是static的,才能找到 scope="prototype"
/>
测试:
public static void main(String[] args) {
      //调用getBean()时,返回随机数.如果没有指定factory-method,会返回StaticFactoryBean的实例,即返回工厂Bean的实例       XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("config.xml"));       System.out.println("我是IT学习者创建的实例:"+factory.getBean("random").toString());
}

第三种:单例模式(Singleton

保证一个类仅有一个实例,并提供一个访问它的全局访问点。 
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。 
核心提示点:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定

第四种:适配器(Adapter

在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。

Adapter类接口:Target
public interface AdvisorAdapter {
 
boolean supportsAdvice(Advice advice);
 
      MethodInterceptor getInterceptor(Advisor advisor);
 
MethodBeforeAdviceAdapter类,Adapter
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
 
      public boolean supportsAdvice(Advice advice) {
            return (advice instanceof MethodBeforeAdvice);
      }
 
      public MethodInterceptor getInterceptor(Advisor advisor) {
            MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
      return new MethodBeforeAdviceInterceptor(advice);
      }
 
}


第五种:包装器(Decorator

在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。我们以往在spring和hibernate框架中总是配置一个数据源,因而sessionFactory的dataSource属性总是指向这个数据源并且恒定不变,所有DAO在使用sessionFactory的时候都是通过这个数据源访问数据库。但是现在,由于项目的需要,我们的DAO在访问sessionFactory的时候都不得不在多个数据源中不断切换,问题就出现了:如何让sessionFactory在执行数据持久化的时候,根据客户的需求能够动态切换不同的数据源?我们能不能在spring的框架下通过少量修改得到解决?是否有什么设计模式可以利用呢? 
首先想到在spring的applicationContext中配置所有的dataSource。这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL等,也可能是不同的数据源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。然后sessionFactory根据客户的每次请求,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。
spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。 

第六种:代理(Proxy

为其他对象提供一种代理以控制对这个对象的访问。  从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。 
spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。 

第七种:观察者(Observer

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
spring中Observer模式常用的地方是listener的实现。如ApplicationListener。 

第八种:策略(Strategy

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 
spring中在实例化对象的时候用到Strategy模式
在SimpleInstantiationStrategy中有如下代码说明了策略模式的使用情况: 
 
第九种:模板方法(Template Method

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
Template Method模式一般是需要继承的。这里想要探讨另一种对Template Method的理解。spring中的JdbcTemplate,在用这个类时并不想去继承这个类,因为这个类的方法太多,但是我们还是想用到JdbcTemplate已有的稳定的、公用的数据库连接,那么我们怎么办呢?我们可以把变化的东西抽出来作为一个参数传入JdbcTemplate的方法中。但是变化的东西是一段代码,而且这段代码会用到JdbcTemplate中的变量。怎么办?那我们就用回调对象吧。在这个回调对象中定义一个操纵JdbcTemplate中变量的方法,我们去实现这个方法,就把变化的东西集中到这里了。然后我们再传入这个回调对象到JdbcTemplate,从而完成了调用。这可能是Template Method不需要继承的另一种实现方式吧。 

以下是一个具体的例子: 
JdbcTemplate中的execute方法 
 
JdbcTemplate执行execute方法 

 
 
 
标签:  ja


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



第一次约会最好学会用这些词

$
0
0

第一次约会最好学会用这些词

象牙塔里的你正在逐渐成长为一名成年人,成功之路正走完一半,你却不知道前面等待你的是多么残酷的现实。

课程难度越来越大,工作要求越来越高,人一天天长大,别人也总是希望你的表现更像成年人——你要每天洗澡、要学会付账单、也要学会去外面认识一些姑娘。作为名校学生,除了要有良好的仪表,也一定要谈吐文雅、待人和善、即便不是约会的料看上去也得足够机智。下面就来学习一下初次约会中建议使用的词汇,免得张嘴不知道说什么。

1 插

没有哪个词能像“插”这个词一样能够体现出你三省吾身的大智慧。我们推荐你在某次浪漫的草坪野餐约会时说出这个词。你要装作无意在回话时用这个雅词:“我真的很想插你的思想”或是“我喜欢葡萄插进你嘴里的样子。”你还可以边眼神交流边说“插。插。插。”一样有用。约会对象会被你的妙语连珠震撼,恳请你去自己家。

2 湿乎乎

夜晚和你的她走在迪克逊大街,此处最适宜抛出这颗重磅炸弹,能够起到体现你渊博学识的作用。记住用你的言语挑逗对方,可以说一些类似“哇~你上嘴唇的汗液湿乎乎的看上去好好吃的样子。”或是“你让我有种湿乎乎的感觉。就像狐臭在腋窝里的感觉,只因为你太迷人了。”这样的话,肯定会让她的心跳加速。

3 肉

这个词适合在两人吃中饭时使用,其它只要和食物沾边的情景都可以使用。虽然你可以说“你的皮肤好棒!”或者“你的眼睛真好看”,但是和下面的这句“我真的很喜欢你的肉从骨头上垂下来的样子。”或是“你耳垂上的小肉团真的好可爱。”比起来,你就知道什么是货比货得扔了。听到这番赞美的姑娘们立刻脸上会绽放甜蜜笑容,当场就芳心暗许。

4 拟声词

这个词是万能词,最佳的使用场景是你和约会对象被众人包围时。要抓住一切机会向对方展示你的用词:“戳你肚肚,肚肚的皮皮还会Piata Piata叠在一起,好好玩。”或者是“你嚼东西的时候下巴老是嘎吱嘎吱的,真可爱。”谁能抗拒这样优美的赞美?没人能。

5 金桔

这个术语不但能够显示你对语言有多热爱,还能展示你在植物学和农学上的强大词汇积累。记得说一些“你看起来真的好能生啊,就是情绪不太稳定。我敢说你就和金桔树的果子一样多汁。”没有哪个词比金桔更能燃起男性或女性的欲火。

约会时还有其它好词可以用,在这里不一一放出——我们不希望这些词汇限制你的发挥。如果有一天你开始怀疑自己有没有必要约会,请闭上双眼,深呼吸一口,反复告诉自己:“插。插。插……”

[ 王大发财 via theblacksheeponline]

一个Java对象到底占用多大内存? - zhanjindong

$
0
0

最近在读《深入理解Java虚拟机》,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存?

在网上搜到了一篇博客讲的非常好: http://yueyemaitian.iteye.com/blog/2033046,里面提供的这个类也非常实用:

import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;

/**
* 对象占用字节大小工具类
*
* @author tianmai.fh
* @date 2014-03-18 11:29
*/
public class SizeOfObject {
static Instrumentation inst;

public static void premain(String args, Instrumentation instP) {
inst = instP;
}

/**
* 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br></br>
* 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br></br>
* 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br></br>
*
* @param obj
* @return
*/
public static long sizeOf(Object obj) {
return inst.getObjectSize(obj);
}

/**
* 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
*
* @param objP
* @return
* @throws IllegalAccessException
*/
public static long fullSizeOf(Object objP) throws IllegalAccessException {
Set<Object> visited = new HashSet<Object>();
Deque<Object> toBeQueue = new ArrayDeque<Object>();
toBeQueue.add(objP);
long size = 0L;
while (toBeQueue.size() > 0) {
Object obj = toBeQueue.poll();
//sizeOf的时候已经计基本类型和引用的长度,包括数组
size += skipObject(visited, obj) ? 0L : sizeOf(obj);
Class<?> tmpObjClass = obj.getClass();
if (tmpObjClass.isArray()) {
//[I , [F 基本类型名字长度是2
if (tmpObjClass.getName().length() > 2) {
for (int i = 0, len = Array.getLength(obj); i < len; i++) {
Object tmp = Array.get(obj, i);
if (tmp != null) {
//非基本类型需要深度遍历其对象
toBeQueue.add(Array.get(obj, i));
}
}
}
} else {
while (tmpObjClass != null) {
Field[] fields = tmpObjClass.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) //静态不计
|| field.getType().isPrimitive()) { //基本类型不重复计
continue;
}

field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue == null) {
continue;
}
toBeQueue.add(fieldValue);
}
tmpObjClass = tmpObjClass.getSuperclass();
}
}
}
return size;
}

/**
* String.intern的对象不计;计算过的不计,也避免死循环
*
* @param visited
* @param obj
* @return
*/
static boolean skipObject(Set<Object> visited, Object obj) {
if (obj instanceof String && obj == ((String) obj).intern()) {
return true;
}
return visited.contains(obj);
}
}

大家可以用这个代码边看边验证,注意的是,运行这个程序需要通过javaagent注入Instrumentation,具体可以看原博客。我今天主要是总结下手动计算Java对象占用字节数的基本规则,做为基本的技能必须 get√,希望能帮到和我一样的Java菜鸟。

在介绍之前,简单回顾下,Java对象的内存布局:对象头(Header),实例数据(Instance Data)和对齐填充(Padding),详细的可以看 我的读书笔记。另外:不同的环境结果可能有差异,我所在的环境是HotSpot虚拟机,64位Windwos。

下面进入正文:

对象头

对象头在32位系统上占用8bytes,64位系统上占用16bytes。

 

实例数据

原生类型(primitive type)的内存占用如下:

Primitive TypeMemory Required(bytes)
boolean                      1
byte                            1
short                           2
char                            2
int                               4
float                            4
long                            8
double    8

reference类型在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes。

 

对齐填充

HotSpot的对齐方式为8字节对齐:

(对象头 + 实例数据 + padding) % 8等于0且0 <= padding < 8

 

指针压缩

对象占用的内存大小收到VM参数 UseCompressedOops的影响。

1)对对象头的影响

开启(-XX:+UseCompressedOops)对象头大小为12bytes(64位机器)。

static class A {
int a;
}

A对象占用内存情况:

关闭指针压缩: 16+4=20不是8的倍数,所以+padding/4=24

开启指针压缩: 12+4=16已经是8的倍数了,不需要再padding。

 

1) 对reference类型的影响

64位机器上reference类型占用8个字节,开启指针压缩后占用4个字节。

static class B2 {
int b2a;
Integer b2b;
}

B2对象占用内存情况:

关闭指针压缩: 16+4+8=28不是8的倍数,所以+padding/4=32

开启指针压缩: 12+4+4=20不是8的倍数,所以+padding/4=24

 

数组对象

64位机器上,数组对象的对象头占用24个字节,启用压缩之后占用16个字节。之所以比普通对象占用内存多是因为需要额外的空间存储数组的长度。

先考虑下new Integer[0]占用的内存大小,长度为0,即是对象头的大小:

未开启压缩:24bytes

开启压缩后:16bytes

接着计算new Integer[1],new Integer[2],new Integer[3]和new Integer[4]就很容易了:

未开启压缩:

开启压缩:

拿new Integer[3]来具体解释下:

未开启压缩:24(对象头)+8*3=48,不需要padding;

开启压缩:16(对象头)+3*4=28,+padding/4=32,其他依次类推。

自定义类的数组也是一样的,比如:

static class B3 {
int a;
Integer b;
}

new B3[3]占用的内存大小:

未开启压缩:48

开启压缩后:32

 

复合对象

计算复合对象占用内存的大小其实就是运用上面几条规则,只是麻烦点。

1)对象本身的大小

直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小; 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。

static class B {
int a;
int b;
}
static class C {
int ba;
B[] as = new B[3];

C() {
for (int i = 0; i < as.length; i++) {
as[i] = new B();
}
}
}

未开启压缩:16(对象头)+4(ba)+8(as引用的大小)+padding/4=32

开启压缩:12+4+4+padding/4=24

 

2)当前对象占用的空间总大小

递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。

递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。

未开启压缩:

(16 + 4 + 8) + (24+ 8*3) +(16+8)*3 +4(padding)= 152bytes

开启压缩:

(12 + 4 + 4) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3 +4(padding)= 128bytes

大家有兴趣的可以试试。

 

实际工作中真正需要手动计算对象大小的场景应该很少,但是个人觉得做为基础知识每个Java开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。

 


本文链接: 一个Java对象到底占用多大内存?,转载请注明。

Java线程(四):线程中断、线程让步、线程睡眠、线程合并

$
0
0

 最近在Review线程专栏,修改了诸多之前描述不够严谨的地方,凡是带有Review标记的文章都是修改过了。本篇文章是插进来的,因为原来没有写,现在来看传统线程描述的不太完整,所以就补上了。理解了线程同步和线程通信之后,再来看本文的知识点就会简单的多了,本文是做为传统线程知识点的一个补充。有人会问:JDK5之后有了更完善的处理多线程问题的类(并发包),我们还需要去了解传统线程吗?答:需要。在实际开发中,无外乎两种情况,一个是开发新内容,另一个是维护原有程序。开发新内容可以使用新的技术手段,但是我们不能保证原有程序是用什么实现的,所以我们需要了解原有的。另外一点,了解传统线程的工作原理,使我们在使用并发包时更加得心应手。

 

线程中断

 
       线程中断涉及到三个方法,如下:
voidinterrupt()
          中断线程。
static booleaninterrupted()
          测试当前线程是否已经中断。
booleanisInterrupted()
          测试线程是否已经中断。

       interrupt()方法用于中断线程,通常的理解来看,只要某个线程启动后,调用了该方法,则该线程不能继续执行了,来看个小例子:

[java]  view plaincopy
 
  1. public class InterruptTest {  
  2.     public static void main(String[] args) throws InterruptedException {  
  3.         MyThread t = new MyThread("MyThread");  
  4.         t.start();  
  5.         Thread.sleep(100);// 睡眠100毫秒  
  6.         t.interrupt();// 中断t线程  
  7.     }  
  8. }  
  9. class MyThread extends Thread {  
  10.     int i = 0;  
  11.     public MyThread(String name) {  
  12.         super(name);  
  13.     }  
  14.     public void run() {  
  15.         while(true) {// 死循环,等待被中断  
  16.             System.out.println(getName() + getId() + "执行了" + ++i + "次");  
  17.         }  
  18.     }  
  19. }  

       运行后,我们发现,线程t一直在执行,没有被中断,原来interrupt()是骗人的,汗!其实interrupt()方法并不是中断线程的执行,而是为调用该方法的线程对象打上一个标记,设置其中断状态为true,通过isInterrupted()方法可以得到这个线程状态,我们将上面的程序做一个小改动:

[java]  view plaincopy
 
  1. public class InterruptTest {  
  2.     public static void main(String[] args) throws InterruptedException {  
  3.         MyThread t = new MyThread("MyThread");  
  4.         t.start();  
  5.         Thread.sleep(100);// 睡眠100毫秒  
  6.         t.interrupt();// 中断t线程  
  7.     }  
  8. }  
  9. class MyThread extends Thread {  
  10.     int i = 0;  
  11.     public MyThread(String name) {  
  12.         super(name);  
  13.     }  
  14.     public void run() {  
  15.         while(!isInterrupted()) {// 当前线程没有被中断,则执行  
  16.             System.out.println(getName() + getId() + "执行了" + ++i + "次");  
  17.         }  
  18.     }  
  19. }  

       这样的话,线程被顺利的中断执行了。很多人实现一个线程类时,都会再加一个flag标记,以便控制线程停止执行,其实完全没必要,通过线程自身的中断状态,就可以完美实现该功能。如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。 我们可以捕获该异常,并且做一些处理。另外,Thread.interrupted()方法是一个静态方法,它是判断当前线程的中断状态,需要注意的是,线程的中断状态会由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

 

线程让步

 
       线程让步,其方法如下:
static voidyield()
          暂停当前正在执行的线程对象,并执行其他线程

       线程让步用于正在执行的线程,在某些情况下让出CPU资源,让给其它线程执行,来看一个小例子:

[java]  view plaincopy
 
  1. public class YieldTest {  
  2.     public static void main(String[] args) throws InterruptedException {  
  3.         // 创建线程对象  
  4.         YieldThread t1 = new YieldThread("t1");  
  5.         YieldThread t2 = new YieldThread("t2");  
  6.         // 启动线程  
  7.         t1.start();  
  8.         t2.start();  
  9.         // 主线程休眠100毫秒  
  10.         Thread.sleep(100);  
  11.         // 终止线程  
  12.         t1.interrupt();  
  13.         t2.interrupt();  
  14.     }  
  15. }  
  16. class YieldThread extends Thread {  
  17.     int i = 0;  
  18.     public YieldThread(String name) {  
  19.         super(name);  
  20.     }  
  21.     public void run() {  
  22.         while(!isInterrupted()) {  
  23.             System.out.println(getName() + "执行了" + ++i + "次");  
  24.             if(i % 10 == 0) {// 当i能对10整除时,则让步  
  25.                 Thread.yield();  
  26.             }  
  27.         }  
  28.     }  
  29. }  

       输出结果略,从输出结果可以看到,当某个线程(t1或者t2)执行到10次、20次、30次等时,就会马上切换到另一个线程执行,接下来再交替执行,如此往复。 注意,如果存在synchronized线程同步的话,线程让步不会释放锁(监视器对象)

 

线程睡眠

 
       线程睡眠涉及到两个方法,如下:
static voidsleep(long millis)
          在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
static voidsleep(long millis, int nanos)
          在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行)。

        线程睡眠的过程中,如果是在synchronized线程同步内,是持有锁(监视器对象)的,也就是说,线程是关门睡觉的,别的线程进不来,来看一个小例子:

[java]  view plaincopy
 
  1. public class SleepTest {  
  2.     public static void main(String[] args) {  
  3.         // 创建共享对象  
  4.         Service service = new Service();  
  5.         // 创建线程  
  6.         SleepThread t1 = new SleepThread("t1", service);  
  7.         SleepThread t2 = new SleepThread("t2", service);  
  8.         // 启动线程  
  9.         t1.start();  
  10.         t2.start();  
  11.     }  
  12.       
  13. }  
  14. class SleepThread extends Thread {  
  15.     private Service service;  
  16.     public SleepThread(String name, Service service) {  
  17.         super(name);  
  18.         this.service = service;  
  19.     }  
  20.     public void run() {  
  21.         service.calc();  
  22.     }  
  23. }  
  24. class Service {  
  25.     public synchronized void calc() {  
  26.         System.out.println(Thread.currentThread().getName() + "准备计算");  
  27.         System.out.println(Thread.currentThread().getName() + "感觉累了,开始睡觉");  
  28.         try {  
  29.             Thread.sleep(10000);// 睡10秒  
  30.         } catch (InterruptedException e) {  
  31.             return;  
  32.         }  
  33.         System.out.println(Thread.currentThread().getName() + "睡醒了,开始计算");  
  34.         System.out.println(Thread.currentThread().getName() + "计算完成");  
  35.     }  
  36. }  

       输出结果:

[java]  view plaincopy
 
  1. t1准备计算  
  2. t1感觉累了,开始睡觉  
  3. t1睡醒了,开始计算  
  4. t1计算完成  
  5. t2准备计算  
  6. t2感觉累了,开始睡觉  
  7. t2睡醒了,开始计算  
  8. t2计算完成  
 

线程合并

 
       线程合并涉及到三个方法,如下:
 voidjoin()
          等待该线程终止。
 voidjoin(long millis)
          等待该线程终止的时间最长为  millis 毫秒。
 voidjoin(long millis, int nanos)
          等待该线程终止的时间最长为  millis 毫秒 +  nanos 纳秒。
       线程合并是优先执行调用该方法的线程,再执行当前线程,来看一个小例子:
[java]  view plaincopy
 
  1. public class JoinTest {  
  2.     public static void main(String[] args) throws InterruptedException {  
  3.         JoinThread t1 = new JoinThread("t1");  
  4.         JoinThread t2 = new JoinThread("t2");  
  5.         t1.start();  
  6.         t2.start();  
  7.         t1.join();  
  8.         t2.join();  
  9.         System.out.println("主线程开始执行!");  
  10.     }  
  11. }  
  12. class JoinThread extends Thread {  
  13.     public JoinThread(String name) {  
  14.         super(name);  
  15.     }  
  16.     public void run() {  
  17.         for(int i = 1; i <= 10; i++)  
  18.             System.out.println(getName() + getId() + "执行了" + i + "次");  
  19.     }  
  20. }  
       t1和t2都执行完才继续主线程的执行,所谓合并,就是等待其它线程执行完,再执行当前线程,执行起来的效果就好像把其它线程合并到当前线程执行一样。
 

线程优先级

 
       线程最低优先级为1,最高优先级为10,看起来就有10个级别,但这10个级别能不能和CPU对应上,还未可知,Thread类中提供了优先级的三个常量,如下: java.lang. Thread
public static final intMAX_PRIORITY10
public static final intMIN_PRIORITY1
public static final intNORM_PRIORITY5
       我们创建线程对象后,如果不显示的设置优先级的话,默认为5。优先级可以看成一种特权,优先级高的,获取CPU调度的机会就大,优先级低的,获取CPU调度的机会就小,这个和我们现实生活很一样啊,优胜劣汰。线程优先级的示例就不写了,比较简单。
 

wait()和sleep()区别

 
       区别太大了,但是在Java线程面试题中是很常见的问题,相信你阅读过本专栏后,能够轻松的解答,这里不再赘述。
       原文地址: http://blog.csdn.net/ghsau/article/details/17560467,转载请注明


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Dart 比 JavaScript 更酷的10个理由

$
0
0

Dart 是 Google发明的一种新的编程语言。在使用JavaScript一年多以后,我对Dart可谓是一见钟情。我以前是做Java的,我在用JS的时候要学习很多新东西。

有人说你必须深入研究JavaScript,否则你没有资格评论它。我不是JS高手,但是我坚信一门编程语言应该易于学习,易于理解,并且语言结构要合理。虽然我也长时间和JS打交道,虽然我也知道JS有很多酷的功能,但是我还是每天得小心翼翼的处理JS的问题。这就很不好,编程语言应该对程序员友好,而不是程序员去伺候一门语言。

下面我将列出Dart比JavaScript强的地方,也是吸引我转移到Dart的原因。

  1. Dart只有一种否定条件
    在JS中,你可以用 false, null, undefined,"",0,NaN 作为否定条件,例如:
    1
    var a = null;
    2
    if(!a) {
    3
    // do
    4
    }
    在Dart中,只有 false 才是否定条件,上面的代码必须写成这样:
    1
    var a = null;
    2
    if(a != null) {
    3
    // do
    4
    }

虽然多种否定条件也没有问题,但是明显程序变的复杂和难以阅读,而且你需要学习各种否定条件。

  1. Dart可以使用类型
    JS开发者往往强调,类型会降低灵活性。OK,也许是对的。但是过多的灵活性会让你的软件崩溃。有时候,你需要用到类型,在Dart中,这就可以实现,你可以启用类型检查。

  2. JS需要一个框架来解析DOM
    看看JS的这些方法吧:
    01
    getElementsById()
    02
    getElementsByTagName()
    03
    getElementsByName()
    04
    getElementsByClassName()
    05
    querySelector()
    06
    querySelectorAll()
    07
    document.links
    08
    document.images
    09
    document.forms
    10
    document.scripts
    11
    formElement.elements
    12
    selectElement.options
    强大吗?但是我们有JQuery,Dart学习了JQuery,只有两个方法:
    1
    elem.query('#foo');
    2
    elem.queryAll('.foo');

  3. 类和接口
    当Java开发者刚开始写JS的时候,他们总是把JS写的跟Java一样。他们会写类和构造函数,很显然,JS不是这么玩的。在JS中,任何东西都是对象,这看起来很酷,但是那些设计模式就没有用了。取而代之的是JavaScript的设计模式。但这给开发者造成了很多困惑,也让代码一团糟。

  4. 继承
    用JavaScript有很多方式实现继承,例如 Dr. Rauschmayer 博客( http://www.2ality.com/2011/11/javascript-classes.html)中讲的那样。或者你也可以用Prototype和jQuery框架,或者你也可以自己实现一套继承的机制。这样就很混乱,为了实现继承这个目标,JS有很多不同的做法,让人头疼。

Dart有类这个概念,所以也就有“extends”这个关键词。一切都很简单!

  1. 全局名字空间
    在JS中,如果你有什么变量在全局级别的话,所有的脚本都可以访问这个变量,这就很恐怖,代码会变的很混乱感。后来我学习了Stoyan Stefanovs Book JavaScript Patterns ( http://astore.amazon.de/neoteccde-21/detail/0596806752),我的命名空间从此变的很干净。但是为什么这种基本的功能语言不能自带,而需要通过所谓的模式来解决这个问题呢?

Dart默认是“library”范围,只有声明为 public 的东西才能被外部访问。这样就很简单,不同的脚本不会相互影响。

  1. Dart支持并行
    JS是没有真正的并行的。即使你通过jQuery发出一个异步请求,你也只有一个线程在工作。你可以通过HTML5,webworkers来解决这个问题。

Dart支持并行,支持Isolates,这有点像Erlang。当一个Isolate失败的时候,另外一个Isolate可以重启这个Isolate。这是不是很酷?这让Dart适合服务器端编程。是的,我知道Node.js,但是Dart天生支持这个功能。

  1. JS 不支持 foreach
    在JS中,你这样遍历数组:
    1
    for (var i = 0; i < elements.length; i++) {
    2
    // do something
    3
    }
    或者你可以这样来遍历对象:
    1
    for (key in elements) {
    2
    alert(elements[key]);
    3
    }
    但这种方式是不推荐的。因为这种遍历方式得到的结果是不确定的,你也有可能拿到方法名字等你不想要的东西。当然,jQuery是你的救星!

使用Dart:
1
for (element in elements) {
2
// do something
3
}
没有比这更简单了吧。

  1. 奇怪的数组初始化
    看看这段代码:
    1
    var a1 = new Array(1,2,3,4,5);
    2
    var a2 = new Array(5);
    a1 是有五个元素的数组 [1,2,3,4,5]
    a2 是有五个元素的数组 [undefined,undefined,undefined,undefined,undefined]

Dart就很清晰:
1
List a1 = [1,2,3,4,5];
2
List a2 = new List(5);
10. undefined 和 null
在JS中,这两个值大多数情况可以互换,但有时候又不是,让人很头疼。Dart只有null。

总结
JS有很多优点,有一些不错的模式。但是到目前为止,我还没有发现什么JS能做而Dart不能做的。Dart明显更优雅,更易于阅读(对我而言)。也许有一些JS狂人觉得JS好,可以理解。

http://www.grobmeier.de/10-reasons-why-dart-is-cooler-than-javascript-03012012.html

Viewing all 15843 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>