qq2009 好友栏目拖一下cpu一下子飙升到50% 并且qq出现假死状态
不明白什么原因 后觉得屏幕取词有点麻烦 就将金山词霸屏幕取词关闭了 
再看qq ,拖动速度很快也没有出现假死状态
遂又开启屏幕取词,再看qq 又变慢了
取消屏幕取词后,就正常了
可见 是两个软件存在冲突了

纯粹灌水了, 下班前灌水一篇,如果tx的人员看到了 麻烦确认下
posted @ 2009-06-17 17:30 雨中漫步的太阳 阅读(47) | 评论 (4)编辑

问题的原因是字符串ANSI和Unicode编码的区别,
VC6与VS2003等默认使用ANSI编码,而VS2005默认采用Unicode.
简单的说,ANSI用1个字节表示字符,Unicode用2个字节表示1个字符.
若想要你的代码在VS2005中编译通过,3中方法:
1.可修改编码选项:项目属性-->配置属性-->常规-->字符集-->使用多字节字符集
2.把你字符串定义为宽字符串,例如:
------WCHAR szName[128] ;
------CreateWindow ( L"这里为类名",…… ) ; // 这里L为宽字符串宏定义
3.显式指定API版本:把WNDCLASS改为WNDCLASSA,把CreateWindow改为CreateWindowA。
对于Win32中与字符串相关的API一般有两个版本Ansi版和Unicode版。
例如CreateWindowA和CreateWindowW。
通常在使用过程中不显式指定,如果在VC6中使用CreateWindow则编译器就使用A版,如果在VS2005中使用CreateWindow则编译器就使用W版。
然而在开发过程中可以显式指定。

posted @ 2009-06-17 09:43 雨中漫步的太阳 阅读(18) | 评论 (0)编辑
     摘要: 第二道算法题(500分)题目要求:双倍超立方数是指一个正整数可以正好被拆分为两种不同的a^3+b^3的方式,其中a,b均为整数且0<a<=b。对于任何一个指定的 int n, 返回所有的小于等于n的双倍超立方数的个数。看到坛子里面有人发的帖子 是关于有道第二题的,饶有兴趣,自己也写了一个算法,效率上面应该比引用文章的效率会高点,具体情况请大家测试吧http://www.cnblogs.... 阅读全文
posted @ 2009-06-03 19:17 雨中漫步的太阳 阅读(980) | 评论 (8)编辑

***为什么要使用commons-logging+log4j
commons-logging和log4j都是[[Apache:http://www.apache.org]]下的开源项目。~
commons-logging的目的是为“所有的Java日志实现”提供一个统一的接口,使项目与日志实现工具解耦,它自身的日志功能比较弱(只有一个简单的 SimpleLog),所以一般不会单独使用它。~
Log4j的功能非常强大,是目前最主流的java日志工具。~
结合使用2者可以避免使项目与log4j紧密耦合,用户可以轻松切换到其他日志工具,同时又可以使用log4j的强大功能。~
***commons-logging如何自动选择适当的日志实现工具
我们在使用commons-logging+日志实现工具时,我们的代码只需要和commons-logging打交道,又commons- logging去选择适当的日志实现工具。这里我们看一下commons-logging是如何去选择实现工具的~
-首先在classpath下寻找自己的配置文件commons-logging.properties,如果找到,则使用其中定义的Log实现类
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
上面这个配置,commons-logging会使用commons-logging的SimpleLog
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
这个配置,commons-logging就会选择使用log4j
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
这个配置,commons-logging会选择jdk的logger
-如果找不到commons-logging.properties文件,则在查找是否已定义系统环境变量org.apache.commons.logging.Log,找到则使用其定义的Log实现类
-否则,查看classpath中是否有Log4j的包,如果发现,则自动使用Log4j作为日志实现类
-否则,使用JDK自身的日志实现类(JDK1.4以后才有日志实现类)
-否则,使用commons-logging自己提供的一个简单的日志实现类SimpleLog
可见,commons-logging总是能找到一个日志实现类,并且尽可能找到一个最合适的日志实现类。~
为了简化配置,我们可以不使用commons-logging的配置文件,也不设置commons-logging相关的环境变量,只需将log4j的包 放入classpath就可以了,这样就可以完成commons-logging与Log4j的结合。如果以后不想使用log4j,只需将log4j的包 从classpath中移除就可以了。
***如何在代码中输出日志
-导入所需commons-logging的类~
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-在自己的类中定义一个org.apache.commons.logging.Log类的私有静态类变量
private static Log log = LogFactory.getLog(ClassName.class);
-使用静态类变量输出日志信息~
为了方便的控制日志输出,把日志分成了不同的级别,从低到高分别是调试,信息,警告,错误,致命错误。这样我们可以通过log4j的配置决定只输出某个级 别以上的日志。例如,在开发时我们将debug(调试)及以上的日志全部输出,而在项目正常运行时,设置为只输出warn(警告)及以上的日志。
//输出调试级别的日志信息
log.debug("debug");
//输出信息级别的日志信息
log.info("information");
//输出警告级别的日志信息
log.warn("warning");
//输出错误级别的日志信息
log.error("error");
//输出致命错误级别的日志信息
log.fatal("fatal");
正因为我们可以通过配置文件来设置日志输出的级别,所以写代码时我们并不知道某条日志是不是会真正输出,比如
log.debug("debug");
在设置了日志输出级别为info(信息)或以上的情况下,是不会被真正输出的。~
这种情况下,为了节省资源,我们可以在输出一条日志前加一个判断语句,判断该日志确实会被输出的情况下才去执行输出代码,如下所示
//输出调试级别的日志信息
if(log.isDebugEnabled()){
     log.debug("debug");
}
//输出信息级别的日志信息
if(log.isInfoEnabled()){
     log.info("information");
}
//输出警告级别的日志信息
if(log.isWarnEnabled()){
     log.warn("warning");
}
//输出错误级别的日志信息
if(log.isErrorEnabled()){
     log.error("error");
}
//输出致命错误级别的日志信息
if(log.isFatalEnabled()){
     log.fatal("fatal");
}
***灵活使用log4j
在classpath下创建log4j.properties,下面讲解log4j的主要配置
-Appender~
Appender用来指明将所有的log信息存放到什么地方,Log4j中支持多种appender,如    console、files、GUI components、NT Event Loggers等,一个Logger可以拥有多个Appender,也就是你既可以将Log信息输出到屏幕,同时存储到一个文件中。~
配置Appender的语法
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
...
log4j.appender.appenderName.optionN = valueN
Log4j提供的appender有以下几种:
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生新文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
-Layout~
Layout的作用是控制Appender的输出方式,也就是格式化输出的信息。~
配置Layout的语法
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
....
log4j.appender.appenderName.layout.optionN = valueN
Log4j提供的layout有以下几种:
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:
%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式
例如:%d{yyyy年MMM月dd日HH:mm:ss,SSS},输出类似:2008年4月07日15:10:58,857
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。
例如:Testlog4.main(TestLog4.java:10)
-Logger~
Logger用来定义日志信息的输出级别和输出目的地。Logger可分为两类
log4j.rootLogger 对所有日志输出起作用
log4j.logger.xx.yy 只对xx.yy包下面的日志输出起作用
例如
log4j.rootLogger=WARN,CONSOLE 指定所有日志级别为warn,采用名为CONSOLE的Appender输出
log4j.logger.com.orsoft=DEBUG,FILE 指定com.orsoft包内的日志,级别为DEBUG,采用名为FILE的Appender来输出。
可以看到,Logger存在类似继承的关系,所有其它Logger均继承自log4j.rootLogger,log4j.logger.xx.yy继承自log4j.logger.xx。~
当某条日志符合多个Logger时,如何判断它的输出级别和输出目的地呢?
我的理解是,输出级别由最底层的Logger决定,输出目的地则是互补关系,将会输出到所有符合条件的Logger所指定的Appender。~
例如
log4j.rootLogger=WARN,CONSOLE
log4j.logger.com.orsoft=DEBUG,FILE
log4j.logger.org.aaa=ERROR
对com.orsoft下的日志,输出级别为DEBUG,输出目的地为CONSOLE和FILE~
对org.aaa下的日志,输出级别为ERROR,输出目的地为CONSOLE~
其它包下的日志,输出级别为WARN,输出目的地为CONSOLE~
log4j.rootLogger=WARN,CONSOLE
log4j.logger.com.orsoft=DEBUG,FILE,CONSOLE
log4j.logger.org.aaa=ERROR
如果这样设置,com.orsoft下的日志,输出级别为DEBUG,输出目的地为CONSOLE和FILE,但是CONSOLE会输出2遍,这是因为2个符合条件的Appender都设置了CONSOLE作为目的地。
***Appender和Layout使用的例子


# 应用于控制台

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[thread] n%c[CATEGORY]%n%m[MESSAGE]%n%n

#应用于文件

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


# 应用于文件回滚

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log //文件位置,也可以用变量${java.home}、rolling.log
log4j.appender.ROLLING_FILE.Append=true //true:添加 false:覆盖
log4j.appender.ROLLING_FILE.MaxFileSize=10KB //文件最大尺寸
log4j.appender.ROLLING_FILE.MaxBackupIndex=1 //备份数
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


#应用于socket

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[thread]%n%c[CATEGORY]%n%m[MESSAGE]%n%n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

# 发送日志给邮件

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=web@www.wuset.com
log4j.appender.MAIL.SMTPHost=www.wusetu.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=web@www.wusetu.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

# 用于数据库

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password=
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=SampleMessages.log4j
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout

#自定义Appender

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@cybercorlin.net
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
posted @ 2009-05-15 11:23 雨中漫步的太阳 阅读(128) | 评论 (0)编辑

本文接上文, http://www.cnblogs.com/suyuan/archive/2009/04/17/1438064.html

这篇文章我要介绍的是给rusultMap的xml段中增加节点,具体效果如下:

image

或许你会问为什么要这样做?

首先我来说说key ,key的作用是指定用于生成hash路径所依赖的对象属性.这里要注意的是你指定的这个属性的值必须是唯一的. 而数据库中的id作为主键必须是唯一值,所以我们一般以 id 来生成我们所需的hash路径.

然后来说明下 datasource ,这里的datasource可以有两个选择 file 或者 db 如果是选择file的话 则对应列根据hash路径存储在文件系统中,如果选择db 则存储在数据库中 ,默认是db 可以省略.

明白了以上添加的节点的作用 ,接下来我们来一步步修改程序使之达到我们的目标:

第一步,修改dtd验证文件:

image   image

这里必须修改 我在上一篇已经介绍过了,这里不再过多解释.请参考上图.

对SqlMap 进行解析是通过com.ibatis.sqlmap.engine.builder.xml.SqlMapParser.java 进行的,这里要说明的是由于我们并没有增加新的node,而是仅仅增加了属性,所以我们仅仅在原有的解析的方法上增加对属性的解析就好了

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
parser.addNodelet("/sqlMap/resultMap", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
        String id = state.applyNamespace(attributes.getProperty("id"));
        String resultClassName = attributes.getProperty("class");
        String extended = state.applyNamespace(attributes.getProperty("extends"));
        String xmlName = attributes.getProperty("xmlName");
        String groupBy = attributes.getProperty("groupBy");
        //解析key
        String key = attributes.getProperty("key");
              
        resultClassName = state.getConfig().getTypeHandlerFactory().resolveAlias(resultClassName);
        Class resultClass;
        try {
          state.getConfig().getErrorContext().setMoreInfo("Check the result class.");
          resultClass = Resources.classForName(resultClassName);
        } catch (Exception e) {
          throw new RuntimeException("Error configuring Result.  Could not set ResultClass.  Cause: " + e, e);
        }
        ResultMapConfig resultConf = state
                                     .getConfig()
                                     .newResultMapConfig(id, resultClass, groupBy, extended, xmlName,key);
        state.setResultConfig(resultConf);
      }
    });
注意代码的最后调用了 newResultMapConfig ,这个也要增加key,像一串,我们只要根据程序一步步跟下去逐步增加key就ok了
 
当我们跟到下面这个地方的时候key必须有一个归宿,他的归宿就是ResultMap对象
请看下图:
image 
 
然后我们跳转到ResultMap类,继续看
image 这里我在ResultMap类中增加了三个属性,key就不用解释了 ,
filehandlerpath其实就是指我一直在说的hash路径.下图展示了生成hash路径的方式.
div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
 //生成hash路径
  public void setFilehandlerpath(Object key) {
	  if(key!=null)
	  {
		 filehandlerpath = delegate.getBaseDirectory() + this.resultClass.getSimpleName();
		 String hashkey = String.valueOf(key.hashCode());
		 String  split = "/";
		 StringBuilder sb = new StringBuilder();
	     for(int i=0;i<hashkey.length();i=i+2){
	    	if((i+2)<=hashkey.length()){
	    		sb.append(split).append(hashkey.substring(i,i+2));
	    	}
	    	else
	    	{
	    		sb.append(split).append("0"+hashkey.charAt(i));
	    	}	    	
	     }
	     sb.append(split).append(hashkey).append(".data");
		 filehandlerpath +=  String.format("%s", new Object[] { sb.toString() });
	  }
  }
还有一个属性是hasfilestore 用于表示这个map是否有result存储在文件系统中.
以上就是我们增加key这个属性的过程.
下面我们继续讲解在rusult中增加datasource属性
解析的方式和key类似
image 
result在Ibatis中对应的对象是ResultMapping ,所以datasource最终的归宿在ResultMapping对象
我们来看ResultMapping对象 ,这里我增加了三个属性,这三个属性的作用请看注释.
image 
而对这几个属性的利用请参考下面的代码.
div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
public void addResultMapping(String propertyName, String columnName, Integer columnIndex, Class javaClass, String jdbcType, String nullValue, String notNullColumn, String statementName, String resultMapName, Object impl ,String datasource) {
    errorContext.setObjectId(propertyName + " mapping of the " + resultMap.getId() + " result map");
    TypeHandler handler;
    if (impl != null) {
      if (impl instanceof TypeHandlerCallback) {
        handler = new CustomTypeHandler((TypeHandlerCallback) impl);
      } else if (impl instanceof TypeHandler) {
        handler = (TypeHandler) impl;
      } else {
        throw new RuntimeException("The class '" + impl + "' is not a valid implementation of TypeHandler 
                                   or TypeHandlerCallback");
      }
    } else {
      handler = config.resolveTypeHandler(client.getDelegate().getTypeHandlerFactory(),
                                   resultMap.getResultClass(), propertyName, javaClass, jdbcType, true);
    }
    ResultMapping mapping = new ResultMapping();
    mapping.setPropertyName(propertyName);
    mapping.setColumnName(columnName);
    mapping.setJdbcTypeName(jdbcType);
    mapping.setTypeHandler(handler);
    mapping.setNullValue(nullValue);
    mapping.setNotNullColumn(notNullColumn);
    mapping.setStatementName(statementName);
    mapping.setNestedResultMapName(resultMapName);
    mapping.setDatasource(datasource);
    if(resultMap.getKey()!=null&&resultMap.getKey().equals(propertyName))
    {
    	mapping.setFilehandler(true);
    }
    if (resultMapName != null && resultMapName.length() > 0) {
      resultMap.addNestedResultMappings(mapping);
    }
    mapping.setJavaType(javaClass);
    if (columnIndex != null) {
      mapping.setColumnIndex(columnIndex.intValue());
    } else {
      resultMappingIndex++;
      mapping.setColumnIndex(resultMappingIndex);
    }
    resultMappingList.add(mapping);
    //如果是保存在文件中 则将ResultMap对象中的hasfilestore 置成 true
    if(mapping.isFromfile()){
    	this.sfResultMappingNames.add(mapping.getPropertyName());
    	if(!resultMap.isHasfilestore()){
    		resultMap.setHasfilestore(true);
    	}
    }    
    resultMap.setSfResultMappingNames(sfResultMappingNames);
    resultMap.setResultMappingList(resultMappingList);
  }
 
ok,本章就介绍到这里,不知道你是否看的明白了.没有关系,如果有兴趣就下载一份代码,我们一起来边学边做边讨论吧.
接下来我们将学习image 这个节点的解析和作用.
posted @ 2009-04-24 12:55 雨中漫步的太阳 阅读(1073) | 评论 (3)编辑

使用Windows Live Writer写blog确实是的确非常爽,可是如果经常要粘贴一些代码的话感觉就太不爽了,虽然有SyntaxHighlight 这样优秀的插件供我们使用,但是总也感觉不舒服,比起博客园后台的代码插入工具还是有些逊色,看着不舒服.

其实 SyntaxHighlight是可以自定义代码样式.

于是立即动手改一个自己看着还舒服的代码样式

div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
  <div style="background:#EEEEEE none repeat scroll 0 0;border-color:#7F7F7F;border-style:solid;
  border-width:1px 1px 1px 3px;width:900px;overflow:hidden;">
  <div style="background:#AFAFAF none repeat scroll 0 0;border-bottom:1px dotted #EAEAEA;
  font-weight:bold;padding:4px;">
<img alt="div css xhtml xml Example Source Code" 
style="margin: 0px 2px -3px 0px;" src="http://images.cnblogs.com/cnblogs_com/suyuan/quote.gif"/> 
Example Source Code <span style="font-weight: 100; color:#AFAFAF;">[http://www.cnblogs.com/suyuan/]</span>
</div>
<div style="line-height:140%;padding:6px;"><pre>{highlighted_source_code}</pre></div>

 

这个代码就是本文的代码样式 ,因为我不喜欢出现滚动条 ,所以使用了overflow:hidden,这样你的代码不能太宽了 具体的根据你博客的样式稍微调整就ok了.

如果有更加好看的样式不妨发布出来.

这样当我们使用wlw写日志插入代码至少看起来舒服点.

posted @ 2009-04-24 11:44 雨中漫步的太阳 阅读(725) | 评论 (0)编辑

原文地址:http://www.cnblogs.com/Kevin-moon/archive/2009/04/24/1442469.html

前段时间仔细看过些关于多线程方面的资料,项目中用到线程的地方也不少,可是,当看了Jeffrey的一篇关于锁的文章后,发现自己虽然一直都在使用多线程,但是缺少了做多线程编程需要的思维!所以想从Jeffrey的Optex(锁)入手,来谈谈我从其中体会的东西。
在NET中,我们用的最多的锁机制就是lock,用起来很简单,短短几行程序就可以实现,例如:

//Lock 's Code
public class TestThreading
{
private System.Object lockThis = new System.Object();
public void Function()
    {
lock (lockThis)
        {
// Access thread-sensitive resources.
        }
    }
}

其实我们也明白,lock并不是锁,而是MS提供的一个简便式的写法,真正实现的是Monitor类中的Enter和Exit方法,既然提到了Monitor类也就说下有个需要注意的地方:
    Pulse和PulseAll方法,这两个方法就是把锁状态将要改变的消息通知给等待队列中的线程,不过这时如果等待队列中没有线程,那么该方法就会一直等待下去,直到有等待的线程进入队列,也就是说该方法可能造成类试死锁的情况出现。
上面的lock + 线程(Thread和ThreadPool) = 多线程编程(N%)!?
    对于该公式我曾经的N是80,现在是20。其中有很多东西影响我,让我从80->20,下面的Optex就是一个入口点。


//Optex 's Code
public sealed class Optex : IDisposable {
private Int32 m_Waiters = 0;
private Semaphore m_WaiterLock = new Semaphore(0, Int32.MaxValue);
public Optex() { }
public void Dispose() {
if (m_WaiterLock != null)
      { 
         m_WaiterLock.Close(); 
         m_WaiterLock = null;
      } 
   }
public void Enter() {
      Thread.BeginCriticalRegion();
// Add ourself to the set of threads interested in the Optex
if (Interlocked.Increment(ref m_Waiters) == 1) {
// If we were the first thread to show interest, we got it.
return;
      }
// Another thread has the Optex, we need to wait for it
      m_WaiterLock.WaitOne();
// When WaitOne returns, this thread now has the Optex
   }
public void Exit() {
// Subtract ourself from the set of threads interested in the Optex
if (Interlocked.Decrement(ref m_Waiters) > 0) {
// Other threads are waiting, wake 1 of them
         m_WaiterLock.Release(1);
      }
      Thread.EndCriticalRegion();
   }
}

看完上面的代码,让我增加了两点认识:
1、Thread.BeginCriticalRegion()和Thread.EndCriticalRegion(); 
因为这段时间正好看了一本多线程编程的书,既然将上面方法认为是进入临界区和退出临界区,对于临界区而言,进入该区的数据,在没有退出之前,如果临界区外的程序需要使用它,那么就必须出于等待。所以觉得已经使用临界区,为什么还要使用Semaphore?!
可是,MS只是取了个相同的名字,做的事情完全不同,上面两个方法完全没有临界区的概念,它只是设置一个区域(Begin到End之间),表示该区域内发生线程中断或未处理的异常会影响整个应用程序域。

2、m_Waiters的作用

一开始以为在Enter的时候,直接写上:
            m_WaiterLock.WaitOne();

              Exit的时候,写上:
m_WaiterLock.Release(1);
这样就可以了。m_Waiters有什么意义?!
优化性能,Semaphore是内核对象,我们都知道,要尽量少的进入内核模式,因为这是很消耗性能,所以尽量少的使用内核对象。m_Waiters的意义就在这里,如果只有一个线程使用该锁对象的时候,是不需要去获取和释放的。 OK,上述的东西都是铺垫,铺完了也就进入主题了!
多线程的思维

 
div css xhtml xml Example Source Code Example Source Code [http://www.cnblogs.com/suyuan/]
namespace ThreadConcurrent.Lock
{
    public sealed class Optex : IDisposable
    {
        /// <summary>
        /// 琐的状态
        /// </summary>
        private Int32 m_LockState = c_lsFree;

        /// <summary>
        /// 自由状态
        /// </summary>
        private const Int32 c_lsFree = 0x00000000;
        
        /// <summary>
        /// 被拥有状态
        /// </summary>
        private const Int32 c_lsOwned = 0x00000001;
        
        /// <summary>
        /// 等待的线程数
        /// </summary>
        private const Int32 c_1Waiter = 0x00000002;

        private Semaphore m_WaiterLock = new Semaphore(0, Int32.MaxValue);

        #region 构造函数

        /// <summary>
        /// 
        /// </summary>
        public Optex() { }

        #endregion

        /// <summary>
        /// 请求锁
        /// </summary>
        public void Enter()
        {
            Thread.BeginCriticalRegion();
            while (true)
            {
                Int32 ls = InterlockedOr(ref m_LockState, c_lsOwned);

                //自由状态
                if ((ls & c_lsOwned) == c_lsFree) return;

                // 增加等待的线程数
                if (IfThen(ref m_LockState, ls, ls + c_1Waiter))
                {
                    m_WaiterLock.WaitOne();
                }
            }
        }

        public void Exit()
        {
            // 释放琐
            Int32 ls = InterlockedAnd(ref m_LockState, ~c_lsOwned);

            //无等待的线程
            if (ls == c_lsOwned)
            {
            }
            else
            {
                ls &= ~c_lsOwned;
                if (IfThen(ref m_LockState, ls & ~c_lsOwned, ls - c_1Waiter))
                {
                    m_WaiterLock.Release(1);
                }
                else
                {
                }
            }
            Thread.EndCriticalRegion();
        }

        #region 原子化操作

        /// <summary>
        /// 与操作
        /// </summary>
        /// <param name="target"></param>
        /// <param name="with"></param>
        /// <returns></returns>
        private static Int32 InterlockedAnd(ref Int32 target, Int32 with)
        {
            Int32 i, j = target;
            do
            {
                i = j;
                j = Interlocked.CompareExchange(ref target, i & with, i);
            } while (i != j);
            return j;
        }

        /// <summary>
        /// 或操作
        /// </summary>
        /// <param name="target"></param>
        /// <param name="with"></param>
        /// <returns></returns>
        private static Int32 InterlockedOr(ref Int32 target, Int32 with)
        {
            Int32 i, j = target;
            do
            {
                i = j;
                j = Interlocked.CompareExchange(ref target, i | with, i);
            } while (i != j);
            return j;
        }

        #endregion

        private static Boolean IfThen(ref Int32 val, Int32 @if, Int32 then)
        {
            return (Interlocked.CompareExchange(ref val, @then, @if) == @if);
        }

        private static Boolean IfThen(ref Int32 val, Int32 @if, Int32 then, out Int32 prevVal)
        {
            prevVal = Interlocked.CompareExchange(ref val, @then, @if);
            return (prevVal == @if);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (m_WaiterLock != null)
            {
                m_WaiterLock.Close();
                m_WaiterLock = null;
            }
        }
    }
}
对于上面的这个代码,我晕眩了好一段时间,不过当我真正理解的时候,从晕眩中学到了做多线程编程应该具备的思维方式。 
首先从简单的理解开始谈,
1、原子化操作
     对于InterLocked类,曾经也知道,但是却用的很少,不过从该代码中知道,在多线程的编程中对共享数据的写入操作,一定要达到原子性。
至于如何做到这点,InterlockedAnd和InterlockedOr做了很好的诠释: 
While循环的目的就是保证target值以最新的值做与操作,如果传入的值在执行的过程被其他线程改变的话,那么是不会退出该循环的,
并会利用改变后的值重新做次与操作。


2、理解Enter和Exit
     这两个方法很难写出来解释,用图是最清晰的。

曾经的晕眩:
1、Enter方法中为什么存在循环,为什么不是执行完waitone就结束,必须m_lockState等于c_IsFree的时候才结束?
     线程的执行并不完全按照先前排好的顺序去执行,有时会发生一些特殊的情况来使改变线程的调度顺序,所以就可能会出现上图灰色部分的情况,则为了解决该可能发生的问题(概率很小)循环机制就出现了。
2、为什么在WaitOne和Release之前,除了增加和减少等待者外,还需要判断m_lockstate是否改变(进入Enter到执行Waitone前的这段时间)?
一般性的思维:

该程序的思维:

这样做的好处就是尽量少的操作内核对象,提高性能!
      多线程编程虽然复杂,但是我觉得很有意思和挑战性,而且随着硬件的发展,多线程编程会更加重要,既然已经上路就让我们走到尽头!
posted @ 2009-04-24 09:34 雨中漫步的太阳 阅读(20) | 评论 (0)编辑

虽然有点唬人,但是在实际开发中,确实会遇到此类需求但是要求又不是很严格,那样的话用这个方式还是比较不错的选择

呵呵 以下内容转载 来自csdb论坛

blog文章
http://blog.csdn.net/jinjazz/archive/2009/04/16/4084142.aspx

SQL code
set nocount on
--75151448行数据
select count(*) from syscolumns a,syscolumns b,syscolumns c 
set statistics time on
 
 select top 10 * from(
select a.name as name,left(b.name,10) as name1, checksum(newid()) as hash
    from syscolumns a,syscolumns b,syscolumns c )t
 where hash%100=0
 
set statistics time off
set nocount off

SQL Server 执行时间:
  CPU 时间 = 16 毫秒,占用时间 = 4 毫秒。
这么bt?不过仔细一看是唬人的,这个是伪随机,后面数百万的大部分数据是一辈子都不会有机会显示的。但这是一个思路,where hash%100=0 这句话当中的100是个关键的因素。
要做到真的随机,至少需要hash%700000,同样的机器需要20秒,不过个人觉得已经很不错了。如果是hash%70000则是2秒,可以看出这基本是个线性关系。此思路应该比order by newid更加实用吧,order by newid()的top 10 我在运行了2分半还没有反应后放弃了。
posted @ 2009-04-23 09:51 雨中漫步的太阳 阅读(38) | 评论 (0)编辑

本文接上文

http://www.cnblogs.com/suyuan/archive/2009/04/16/1437360.html

从本篇文章开始我将逐步讲解如果通过修改Ibatis源代码实现上述功能,而本篇先介绍Ibatis下载,编译和sqlmapconfig的解析.此处我们使用的是java版本,.net版本请参考本版本.

下载:

Ibatis的官方网站http://ibatis.apache.org/

你可以通过官方网站下载最新的Ibatis源代码.

官方提供的源码中是不含依赖包的.仅仅提供了一份依赖包清单,并且还没有列全.同时官方给的清单中个别包已经升级而老版本下载已经不再提供,我们尽量找和官方提供清单中最接近的版本.否则可能会造成编译不通过.

如果你觉得麻烦,我这里提供了官方所列清单中的依赖包

  /Files/suyuan/IbatisNeedlib.rar

下载源代码,并且附加了依赖包后,请注意,ibatis是在jdk1.5环境下面编译的通过,如果你选择的是jdk1.6,请更改设置,否则编译错误.

 

下面开始动刀了,呵呵

 

上篇文章中,我们已经介绍了要在sqlmaperconfig文件中增加一个节点

<BaseDirectory resource=”d:/ibatis/”/>

这个节点的作用就是指定文件系统存储根路径.

Ibatis初始化的时候会根据sql-map-2.dtd sql-map-config-2.dtd 验证xml文件是否正确,如果我们之间在sqlmaperconfig 中增加该节点就会初始化出错.

首先我们修改sql-map-config-2.dtd文件

然后还要定义这个节点

完成上面的操作后,xml中增加我们配置的节点 就不会初始化出错了.


仅仅配置完成后,并不起作用,因为还没有解析,还要增加解析的部分.

Ibatis xml的解析 都放在这个package com.ibatis.sqlmap.engine.builder.xml 下面

此处对于sqlmapconfig 解析的类对应的是 SqlMapConfigParser

我们只需要在这个类中增加下面一个方法,并且把这个方法放到 SqlMapConfigParser的构造方法中就可以了.

将这个方法放到构造方法中 其实就是NodeletParser中增加了一个node的处理方法.

 

注意 这句代码

就是把我们解析到的值赋给了一个对象的一个属性.而这个对象就是SqlMapExecutorDelegate,就是说,我们需要在这个对象中增加一个属性是

private String baseDirectory; SqlMapExecutorDelegate 仿佛一个大管家,一样,以后的改造中,我们会多次使用到该对象.

这里假如我们没有在配置文件中 配置 BaseDirectory 节点, 则默认使用当前目录

baseDirectory = System.getProperty("user.dir");

 

 

ok,到现在对于 我们就成功了增加了 BaseDirectory 节点了, 这个配置路径会和以后生成的hash路径组合成我们的文件存储路径.

 

本文到此结束,其余部分将在下文讲解

posted @ 2009-04-17 15:43 雨中漫步的太阳 阅读(1528) | 评论 (3)编辑

 不知道 IbatisHelper 是什么东东的请先参看这里

http://www.cnblogs.com/suyuan/archive/2008/12/26/1362745.html

自从IbatisHelper发布以来,很多朋友给我邮件,需要源代码,以前都是通过email发个需要的人,但是随着收到的email增多,感觉一个个分发好麻烦!

索性直接在这里发布了,需要的自己下载吧!

自己认为自己的代码写的很生硬,如果哪个朋友有精力完善该功能,就再接再厉,目前这个能满足我们的需求就懒得做了.如果你们完善了 就麻烦回馈给我一份代码

废话不多说了 直接提供下载地址吧

/Files/suyuan/IbatisHelper_src.rar

如果对您有帮助 麻烦捧个人场 呵呵~~~~~~~

 另外贴一个比较比较完整的sqlmap模板,目前我们生成就是用这个模板,具体应用自己改吧

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "http://java.plugbase.org/dtd/sql-map-2.dtd"
>

<sqlMap namespace="${table}">
  
<typeAlias alias="${table}" type="${package}.${table}"/>
  
<typeAlias alias="SQLPager" type="org.plugbase.sql.SQLPager"/>
  
<resultMap id="${table}resultMap" class="${table}">
      #foreach($item in $list)
          
<result property="${item.name.ToLower()}" column="${item.name.ToLower()}"/>
    #end
  
</resultMap>

    
<select id="Count${table}" resultClass="int">
        select count(*) from ${table}
    
</select>


    
<select id="Select${table}ById" parameterClass="int" resultMap="${table}resultMap">
        select * from ${table} where id=#value#
    
</select>

    
<insert id="Insert${table}" parameterClass = "${table}">
        insert into ${table}
        (
    #foreach($item in $list)
    #if(${item.name.ToLower()}!="id")
    #if($velocityCount==$list.Count())
    ${item.name.ToLower()}
    #else
    ${item.name.ToLower()},
    #end
    #end
    #end
        )
        values
        (
    #foreach($item in $list)
    #if(${item.name.ToLower()}!="id")
    #if($velocityCount==$list.Count())
    #${item.name.ToLower()}#
    #else
    #${item.name.ToLower()}#,
    #end
    #end
    #end
        )
    
</insert>

    
<update id="Update${table}" parameterClass = "${table}">
        update ${table}
    #foreach($item in $list)
    #if($velocityCount==1)
    set
    #end
    #if(${item.name.ToLower()}!="id")
    #if($velocityCount==$list.Count())
    ${item.name.ToLower()}=#${item.name.ToLower()}#
    #else
    ${item.name.ToLower()}=#${item.name.ToLower()}#,
    #end
    #end
    #end
        where id=#value#
    
</update>

    
<delete id="Delete${table}ById" parameterClass="int">
        delete from ${table} where id=#value#
    
</delete>

</sqlMap>

 

posted @ 2009-04-17 13:47 雨中漫步的太阳 阅读(2839) | 评论 (14)编辑