当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪设计模式学习之路---单例模式(二)                  作者:zuoxiaolong8810(左潇龙),转载请注明出处。             上一章,我们学习了设计模式的概念,以及为什么要学习设计模式,还有在.........
    ▪dmalloc doesn't show log when a program compiled with pthread      Recently I have tried to implement a program to manage my system services. In fact, this is a server-side program, I want it to be a multiple thread program to process multiple requests from client. This program has too many malloc/calloc and free, so .........
    ▪Spring rest对etag支持      原文地址:http://www.javaarch.net/jiagoushi/698.htm Spring rest对etag支持 etag(entity tag)是http响应头中用来判断对应响应结果是否修改。可以使用hash算法来计算etag的值。 比如:第一次访问 curl -H ".........

[1]设计模式学习之路---单例模式(二)
    来源: 互联网  发布时间: 2013-11-19

            作者:zuoxiaolong8810(左潇龙),转载请注明出处。

            上一章,我们学习了设计模式的概念,以及为什么要学习设计模式,还有在进行系统设计时应当遵守的六大原则,本章我们就来开始一一的学习GOF当中的二十三钟设计模式。

            我一会在思考如何去诠释这么多设计模式,因为网上有很多现成的,可供学习的资料,我在想有什么地方可以让各位跟着我的节奏去学习,而不是网上的那些资料,优势在哪里,思考很久,我觉得唯一的优势,或者说我能有的优势,就是简单通俗易懂。

            遵循着中心思想通俗易懂,我们首先来回顾一下单例模式为何要出现,又或者说什么样的类可以做成单例的。

            在我的工作过程中,我发现所有可以使用单例模式的类都有一个共性,那就是这个类没有自己的状态,换句话说,这些类无论你实例化多少个,其实都是一样的。

            我稍微总结一下,一般最容易区别的地方就在于,这些类,都没有非静态的,可设置值的属性。

            我来举个反面教材,即一个不能被做成单例模式的类。

public class NoSingleton {

	private int changedField;
	
	private static int staticChangedField;
	
	private void setChangedField(int value){
		this.changedField = value;
	}
	
	private static void setStaticChangedField(int value){
		staticChangedField = value;
	}
	
}
             上面这个类,有两个属性,一个是静态的,一个是非静态的,而且非静态的属性我们提供了set方法(暂且不考虑突破属性访问权限的反射机制),那么这个类就是具有自己的状态的,因为它有一个实例级别的变量changedField,这个变量在每个实例当中都有可能是不一样的。而静态的则不会有这种担忧,因为它是被这个类的所有实例共享的。

             所以上述这个类不能做成单例的类,一般可以做成单例的类的样子都有以下特点。

             1.所有的对外可变属性都是静态的。

             2.所有的非静态属性都是私有的,并且没有对外公开的可以设置值的方法。

             下面,我们就来看一下做成单例的几种方式。

             首先,我们来看一下最标准也是最原始的单例模式的构造方式。

public class Singleton {

	//一个静态的实例
	private static Singleton singleton;
	//私有化构造函数
	private Singleton(){}
	//给出一个公共的静态方法返回一个单一实例
	public static Singleton getInstance(){
		if (singleton == null) {
			singleton = new Singleton();
		}
		return singleton;
	}
}
            这是在不考虑并发访问的情况下标准的单例模式的构造方式,这种方式通过几个地方来限制了我们取到的实例是唯一的。

            1.静态实例,带有static关键字的属性在每一个类中都是唯一的,此为保证单例的最重要的一步。

            2.限制客户端随意创造实例,即私有化构造方法。

            3.给一个公共的获取实例的静态方法,注意,是静态的方法,因为这个方法是在我们未获取到实例的时候就要提供给客户端调用的,所以如果是非静态的话,那就变成一个矛盾体了,因为非静态的方法必须要拥有实例才可以调用。

            4.判断只有持有的静态实例为null时才调用构造方法创造一个实例,否则就直接返回。

            假如你去面试一家公司,给了你一道题,让你写出一个单例模式的例子,那么如果你是刚出大学校门的学生,你能写出上面这种示例,假设我是面试官的话,满分100的话,我会给90分,剩下的那10分算是给更优秀的人一个更高的台阶。但如果你是一个有过两三年工作经验的人,如果你写出上面的示例,我估计我最多给你30分,甚至心情要是万一不好的话可能会一分不给。

           为什么同样的示例放到不同的人身上差别会这么大,就是因为前面我提到的那个情况,在不考虑并发访问的情况下,上述示例是没有问题的。

           至于为什么在并发情况下上述的例子是不安全的呢,我在这里给各位制造了一个并发的例子,用来说明,上述情况的单例模式,是有可能造出来多个实例的,我自己测试了约莫100次左右,最多的一次,竟然造出了3个实例。下面给出代码,大约运行10次(并发是具有概率性的,10次只是保守估计,也可能一次,也可能100次)就会发现我们创造了不只一个实例。

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestSingleton {
	
	boolean lock ;
	
	public boolean isLock() {
		return lock;
	}

	public void setLock(boolean lock) {
		this.lock = lock;
	}
	
	public static void main(String[] args) throws InterruptedException {
		final Set<String> instanceSet = Collections.synchronizedSet(new HashSet<String>());
		final TestSingleton lock = new TestSingleton();
		lock.setLock(true);
		ExecutorService executorService = Executors.newCachedThreadPool();
		for (int i = 0; i < 100; i++) {
			executorService.execute(new Runnable() {
				
				public void run() {
					while (true) {
						if (!lock.isLock()) {
							Singleton singleton = Singleton.getInstance();
							instanceSet.add(singleton.toString());
							break;
						}
					}
				}
			});
		}
		Thread.sleep(5000);
		lock.setLock(false);
		Thread.sleep(5000);
		System.out.println("------并发情况下我们取到的实例------");
		for (String instance : instanceSet) {
			System.out.println(instance);
		}
		executorService.shutdown();
	}
}
               我在程序中同时开启了100个线程,去访问getInstance方法,并且把获得实例的toString方法获得的实例字符串装入一个同步的set集合,set集合会自动去重,所以看结果如果输出了两个或者两个以上的实例字符串,就说明我们在并发访问的过程中产生了多个实例。

               程序当中让main线程睡眠了两次,第一次是为了给足够的时间让100个线程全部开启,第二个是将锁打开以后,保证所有的线程都已经调用了getInstance方法。

               好了,这下我们用事实说明了,上述的单例写法,我们是可以创造出多个实例的,至于为什么在这里要稍微解释一下,虽说我一直都喜欢用事实说话,包括看书的时候,我也不喜欢作者跟我解释为什么,而是希望给我一个例子,让我自己去印证。

              造成这种情况的原因是因为,当并发访问的时候,第一个调用getInstance方法的线程,在判断完singleton是null的时候,就进入了if块准备创造实例,但是同时另外一个线程在第一个调用的线程还未创造出来之前,就又进行了singleton是否为null的判断,这时singleton依然为null,所以第二个线程也会进入if块去创造实例,这时问题就出来了,有两个线程都进入了if块去创造实例,结果就造成单例模式并非单例。

              为了避免这种情况,我们就要考虑并发的情况了,我们最容易想到的方式应该是下面这样的方式。

public class BadSynchronizedSingleton {

	//一个静态的实例
	private static BadSynchronizedSingleton synchronizedSingleton;
	//私有化构造函数
	private BadSynchronizedSingleton(){}
	//给出一个公共的静态方法返回一个单一实例
	public synchronized static BadSynchronizedSingleton getInstance(){
		if (synchronizedSingleton == null) {
			synchronizedSingleton = new BadSynchronizedSingleton();
		}
		return synchronizedSingleton;
	}
	
}
               上面的做法很简单,就是将整个获取实例的方法同步,这样在一个线程访问这个方法时,其它所有的线程都要处于挂起等待状态,倒是避免了刚才同步访问创造出多个实例的危险,但是我只想说,这样的设计实在是糟糕透了,这样会造成很多无谓的等待,所以为了表示我的愤怒,我在类名上加入Bad。

               其实我们同步的地方只是需要发生在单例的实例还未创建的时候,在实例创

    
[2]dmalloc doesn't show log when a program compiled with pthread
    来源: 互联网  发布时间: 2013-11-19
Recently I have tried to implement a program to manage my system services. In fact, this is a server-side program, I want it to be a multiple thread program to process multiple requests from client. This program has too many malloc/calloc and free, so I used dmalloc to  help to find the unfreed memory. The latest dmalloc version is 5.5.2. Both my Ubuntu and Embedded System use dmalloc-5.5.2. But a weired scenario happens in my Embedded System. It has no log printed. Why the same version dmalloc has different result? Then I compared the dmalloc.h between Ubuntu 13.04 with my Embedded System. They are different, so I think the dmalloc in Ubuntu should have been fixed with a patch. But I don't know where to get the patch? Then I tried to read the pdf file "dmalloc.pdf", which you can find in dmalloc package. Finally, I find a solution from the document. I invoke dmalloc_shutdown() in my program before it exit. Then the log file shows. Note, this scenario only happens when compiled with -lpthread, even if you don't use it actually!
作者:dayancn 发表于2013-6-2 15:55:21 原文链接
阅读:10 评论:0 查看评论

    
[3]Spring rest对etag支持
    来源: 互联网  发布时间: 2013-11-19

原文地址:http://www.javaarch.net/jiagoushi/698.htm

Spring rest对etag支持

etag(entity tag)是http响应头中用来判断对应响应结果是否修改。可以使用hash算法来计算etag的值。

比如:第一次访问

	curl -H "Accept: application/json" -i http://localhost:8080/rest-sec/api/resources/1
	
响应为:

	HTTP/1.1 200 OK
	ETag: "f88dd058fe004909615a64f01be66a7"
	Content-Type: application/json;charset=UTF-8
	Content-Length: 52

那么下次客户端访问的时候If-None-Match或者If-Match头来让服务端判断是否修改


	curl -H "Accept: application/json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"'
	 -i http://localhost:8080/rest-sec/api/resources/1
	
如果没有修改,则服务端会返回

	HTTP/1.1 304 Not Modified
	ETag: "f88dd058fe004909615a64f01be66a7"
	
我们重新修改请求参数:

	curl --user admin@fake.com:adminpass -H "Content-Type: application/json" -i 
	  -X PUT --data '{ "id":1, "name":"newRoleName2", "description":"theNewDescription" }' http://localhost:8080/rest-sec/api/resources/1
	  
响应为:

	HTTP/1.1 200 OK
	ETag: "d41d8cd98f00b204e9800998ecf8427e"
	Content-Length: 0
	
如果我们再访问
	
	curl -H "Accept: application/json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' -i 
	http://localhost:8080/rest-sec/api/resources/1
	
则返回:

	HTTP/1.1 200 OK
	ETag: "03cb37ca667706c68c0aad4cb04c3a211"
	Content-Type: application/json;charset=UTF-8
	Content-Length: 56
	
spring对etag的支持,在web.xml中加上这个filter

	<filter>
	   <filter-name>etagFilter</filter-name>
	   <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
	</filter>
	<filter-mapping>
	   <filter-name>etagFilter</filter-name>
	   <url-pattern>/api/*</url-pattern>
	</filter-mapping>
	
测试etags

第一次判断etag不为空

	@Test
	public void givenResourceExists_whenRetrievingResource_thenEtagIsAlsoReturned() {
		// Given
		Resource existingResource = getApi().create(new Resource());
		String uriOfResource = baseUri + "/" + existingResource.getId();
	 
		// When
		Response findOneResponse = RestAssured.given().
		  header("Accept", "application/json").get(uriOfResource);
	 
		// Then
		assertNotNull(findOneResponse.getHeader(HttpHeaders.ETAG));
	}
	
第二次,我们从上一次取出etag之后把etag发送给服务端验证

	@Test
	public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned() {
		// Given
		T existingResource = getApi().create(createNewEntity());
		String uriOfResource = baseUri + "/" + existingResource.getId();
		Response findOneResponse = RestAssured.given().
		  header("Accept", "application/json").get(uriOfResource);
		String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG);
	 
		// When
		Response secondFindOneResponse= RestAssured.given().
		  header("Accept", "application/json").headers("If-None-Match", etagValue)
		  .get(uriOfResource);
	 
		// Then
		assertTrue(secondFindOneResponse.getStatusCode() == 304);
	}

测试服务端响应结果变化了,则

	@Test
	public void givenResourceWasRetrieved_whenRetrievingAgainWithEtag_thenNotModifiedReturned() {
		// Given
		T existingResource = getApi().create(createNewEntity());
		String uriOfResource = baseUri + "/" + existingResource.getId();
		Response findOneResponse = RestAssured.given().
		  header("Accept", "application/json").get(uriOfResource);
		String etagValue = findOneResponse.getHeader(HttpHeaders.ETAG);
	 
		existingResource.setName(randomAlphabetic(6))
		getApi().update(existingResource.setName(randomString));
	 
		// When
		Response secondFindOneResponse= RestAssured.given().
		  header("Accept", "application/json").headers("If-None-Match", etagValue)
		  .get(uriOfResource);
	 
		// Then
		assertTrue(secondFindOneResponse.getStatusCode() == 200);
	}
	
如果请求带上不正确的etag值并且加上if-match判断,则会返回412Precondition Failed

	@Test
	public void givenResourceExists_whenRetrievedWithIfMatchIncorrectEtag_then412IsReceived() {
		// Given
		T existingResource = getApi().create(createNewEntity());
	 
		// When
		String uriOfResource = baseUri + "/" + existingResource.getId();
		Response findOneResponse = RestAssured.given().header("Accept", "application/json").
		  headers("If-Match", randomAlphabetic(8)).get(uriOfResource);
	 
		// Then
		assertTrue(findOneResponse.getStatusCode() == 412);
	}
	
github示例地址:https://github.com/eugenp/REST


作者:zhongweijian 发表于2013-6-2 16:15:15 原文链接
阅读:20 评论:0 查看评论

    
最新技术文章:
▪主-主数据库系统架构    ▪java.lang.UnsupportedClassVersionError: Bad version number i...    ▪eclipse项目出现红色叉叉解决方案
▪Play!framework 项目部署到Tomcat    ▪dedecms如何做中英文网站?    ▪Spring Batch Framework– introduction chapter(上)
▪第三章 AOP 基于@AspectJ的AOP    ▪基于插件的服务集成方式    ▪Online Coding开发模式 (通过在线配置实现一个表...
▪观察者模式(Observer)    ▪工厂模式 - 程序实现(java)    ▪几种web并行化编程实现
▪机器学习理论与实战(二)决策树    ▪Hibernate(四)——全面解析一对多关联映射    ▪我所理解的设计模式(C++实现)——解释器模...
▪利用规则引擎打造轻量级的面向服务编程模式...    ▪google blink的设计计划: Out-of-Progress iframes    ▪FS SIP呼叫的消息线程和状态机线程
▪XML FREESWITCH APPLICATION 实现    ▪Drupal 实战    ▪Blink: Chromium的新渲染引擎
▪(十四)桥接模式详解(都市异能版)    ▪你不知道的Eclipse用法:使用Allocation tracker跟...    ▪Linux内核-进程
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移
▪第二章 IoC Spring自动扫描和管理Bean    ▪CMMI简介    ▪目标检测(Object Detection)原理与实现(六)
▪值班总结(1)——探讨sql语句的执行机制    ▪第二章 IoC Annotation注入    ▪CentOS 6.4下安装Vagrant
▪Java NIO框架Netty1简单发送接受    ▪漫画研发之八:会吃的孩子有奶吃    ▪比较ASP和ASP.NET
▪SPRING中的CONTEXTLOADERLISTENER    ▪在Nginx下对网站进行密码保护    ▪Hibernate从入门到精通(五)一对一单向关联映...
▪.NET领域驱动设计—初尝(三:穿过迷雾走向光...    ▪linux下的块设备驱动(一)    ▪Modem项目工作总结
▪工作流--JBPM简介及开发环境搭建    ▪工作流--JBPM核心服务及表结构    ▪Eclipse:使用JDepend 进行依赖项检查
▪windows下用putty上传文件到远程Linux方法    ▪iBatis和Hibernate的5点区别    ▪基于学习的Indexing算法
▪设计模式11---设计模式之中介者模式(Mediator...    ▪带你走进EJB--JMS编程模型    ▪从抽象谈起(二):观察者模式与回调
▪设计模式09---设计模式之生成器模式(Builder)也...    ▪svn_resin_持续优化中    ▪Bitmap recycle方法与制作Bitmap的内存缓存
▪Hibernate从入门到精通(四)基本映射    ▪设计模式10---设计模式之原型模式(Prototype)    ▪Dreamer 3.0 支持json、xml、文件上传
▪Eclipse:使用PMD预先检测错误    ▪Jspx.net Framework 5.1 发布    ▪从抽象谈起(一):工厂模式与策略模式
▪Eclipse:使用CheckStyle实施编码标准    ▪【论文阅读】《Chain Replication for Supporting High T...    ▪Struts2 Path_路径问题
▪spring 配置文件详解    ▪Struts2第一个工程helloStruts极其基本配置    ▪Python学习入门基础教程(learning Python)--2 Python简...
▪maven springmvc环境配置    ▪基于SCRUM的金融软件开发项目    ▪software quality assurance 常见问题收录
▪Redis集群明细文档    ▪Dreamer 框架 比Struts2 更加灵活    ▪Maven POM入门
▪git 分支篇-----不断更新中    ▪Oracle非主键自增长    ▪php设计模式——UML类图
▪Matlab,Visio等生成的图片的字体嵌入问题解决...    ▪用Darwin和live555实现的直播框架    ▪学习ORM框架—hibernate(二):由hibernate接口谈...
▪(十)装饰器模式详解(与IO不解的情缘)    ▪无锁编程:最简单例子    ▪【虚拟化实战】网络设计之四Teaming
▪OSGi:生命周期层    ▪Javascript/Jquery——简单定时器    ▪java代码 发送GET、POST请求
▪Entity Framework底层操作封装(3)    ▪HttpClient 发送GET、POST请求    ▪使用spring框架,应用启动时,加载数据
▪Linux下Apache网站目录读写权限的设置    ▪单键模式的C++描述    ▪学习ORM框架—hibernate(一):初识hibernate
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3