Mockito

Mockito 部分mock (partial mock) 部分mock是说一个类的方法有些是实际调用,有些是使用mockito的stubbing (桩实现) 。 为什么需要部分mock 当需要测试一个组合方法 (一个方法需要其它多个方法协作) 的时候,某个叶子方法 (只供别人调用,自己不依赖其它反复) 已经被测试过,我们其实不需要再次测试这个叶子方法,so,让叶子打桩实现返回结果,上层方法实际调用并测试。 mockito实现部分mock的两种方式: spy和 callRealMethod() spy的原理是,如果不打桩默认都会执行真实的方法,如果打桩则返回桩实现。可以看出spy.size()通过桩实现返回了值100,而spy.get(0)则返回了实际值 List<String> list = new LinkedList<String>(); List<String> spy = spy(list); when(spy.size()).thenReturn(100); spy.add("one"); spy.add("two"); assertEquals(spy.get(0), "one"); assertEquals(100, spy.size()); Channel channel = mock(Channel.class); when(channel.writeAndFlush(obj)).thenReturn(null); // 重置 spy 对象,让 add(1,2) 调用真实方法,返回 3 when(exampleService.add(1, 2)).thenCallRealMethod(); Assert.assertEquals(3, exampleService.add(1, 2)); 一、什么是mock测试,什么是mock对象? 一种替代方案就是使用mocks 从图中可以清晰的看出 mock对象就是在调试期间用来作为真实对象的替代品。 mock测试就是在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。 知道什么是mock测试后,那么我们就来认识一下mock框架—Mockito 二、什么是Mockito 除了有一个好记的名字外,Mockito尝试用不一样的方法做mocking测试,是简单轻量级能够替代EasyMock的框架。使用简单,测试代码可读性高,丰富的文档包含在javadoc中,直接在IDE中可查看文档,实例,说明。更多信息: http://code.google.com/p/mockito/ ...

Created 13136-08-13 · Updated 9096-10-09 · 2 min · 284 words · -

Fastjson

Fastjson // 序列化 String text = JSON.toJSONString(obj); // 反序列化 Map<String, Object> foo = JSON.parseObject(jsonStr0, Map.class); fastjson 对象转换时重命名字段名 @JSONField(name="total_count") private int totalCount; @JSONField(name="incomplete_results") private boolean incompleteResults = false; Map<String, Object> userMap = JSON.parseObject(o, new TypeReference<Map<String, Object>>() {}); 使用Fastjson序列化与反序列化对象 public class JSONobject { private String obj; private String color; public String getObj() { return obj; } public void setObj(String obj) { this.obj = obj; } public String getcolor() { return color; } public void setcolor(String color) { this.color = color; } } public class fastjson { public static void main(String[] args) { // TODO Auto-generated method stub JSONobject ins = new JSONobject(); ins.setColor("red"); ins.setObj("s"); //序列化 String text = JSON.toJSONString(ins); System.out.println(text); //反序列化 JSONobject ins1 = JSON.parseObject(text, JSONobject.class); System.out.println(ins1.getColor()); System.out.println(ins1.getObj()); } } 显示的结果是: ...

Created 13136-08-13 · Updated 9096-10-09 · 2 min · 345 words · -

Java 读取环境变量

Java读 环境变量 http://ling091.iteye.com/blog/354052 读取环境变量时可以使用 System.getProperty 或 System.getenv 方法。 System.getProperty 方法 ( JDK1.4 ) 用来读取针对 JVM 的属性,如程序当前的运行路径、路径分隔符、 Java 版本等, ( 见 System.getProperty() 参数大全 ) ,它也可以读取在运行程序时设置的自定义属性。 获取一个JVM已定义属性 //获取系统当前的运行路径 System.out.println("current path = " + System.getProperty("user.dir") ); 输出: current path = E:\program\java\test\Test 获取应用程序的属性: 在命令中输入下面的命令,其中的-D用于设置一个属性 -D<name>=<value> SET myvar=Hello world SET myothervar=nothing java -Dmyvar="%myvar%" -Dmyothervar="%myothervar%" myClass myClass中读取这些属性 String myvar = System.getProperty("myvar"); String myothervar = System.getProperty("myothervar"); 如果要读取操作系统的环境变量 (如 Path 、 TEMP 或 TMP 、 JAVA_HOME 等。) 则可以使用 System.getenv 方法,但是由于某些原因,该方法被去掉了,直到 JDK1.5 后,该方法又被加进去 [3] 。 ...

Created 14146-08-14 · Updated 9096-10-09 · 1 min · 154 words · -

Java Unix Socket

Java Unix Socket http://www.oschina.net/p/juds/similar_projects?lang=0&sort=view Java Unix Domain Sockets (JUDS) 提供了 Java 的方法用来访问 Unix domain sockets socket 。 <dependency> <groupId>uk.co.caprica</groupId> <artifactId>juds</artifactId> <version>0.94.1</version> </dependency> 示例代码: package com.google.code.juds.test; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.google.code.juds.*; public class TestUnixDomainSocket { public static void main(String[] args) throws IOException { if (args.length != 1) { System.out .println("usage: java TestUnixDomainSocket socketfilename"); System.exit(1); } String socketFile = args[0]; byte[] b = new byte[128]; // Testcase 1.1: Test UnixDomainSocketClient with a stream socket UnixDomainSocketClient socket = new UnixDomainSocketClient(socketFile, UnixDomainSocket.SOCK_STREAM); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); in.read(b); System.out.println("Text received: \"" + new String(b) + "\""); String text = "[2] Hello! I'm the client!"; out.write(text.getBytes()); System.out.println("Text sent: " + "\"" + text + "\""); socket.close(); // Testcase 1.2: Test UnixDomainSocketClient with a datagram socket socket = new UnixDomainSocketClient(socketFile, UnixDomainSocket.SOCK_DGRAM); System.out.println("Provoke and catch an " + "UnsupportedOperationException:"); try { in = socket.getInputStream(); } catch (UnsupportedOperationException e) { System.out.println("UnsupportedOperationException has been " + "thrown as expected."); } out = socket.getOutputStream(); text = "[3] Hello! I'm the client!"; out.write(text.getBytes()); System.out.println("Text sent: \"" + text + "\""); socket.close(); // Testcase 2.1: Test UnixDomainSocketServer with a stream socket System.out.println("\nTest #2: Test UnixDomainSocketServer\nTestcase " + "2.1: Test UnixDomainSocketServer with a stream socket..."); UnixDomainSocketServer ssocket = new UnixDomainSocketServer(socketFile, UnixDomainSocket.SOCK_STREAM); in = ssocket.getInputStream(); out = ssocket.getOutputStream(); in.read(b); System.out.println("Text received: \"" + new String(b) + "\""); text = "[5] Hello! I'm the server!"; out.write(text.getBytes()); System.out.println("Text sent: " + "\"" + text + "\""); ssocket.close(); ssocket.unlink(); // Testcase 2.2: Test UnixDomainSocketServer with a datagram socket System.out.println("Testcase 2.2: Test UnixDomainSocketServer with " + "a datagram socket..."); ssocket = new UnixDomainSocketServer(socketFile, UnixDomainSocket.SOCK_DGRAM); System.out.println("Provoke and catch an " + "UnsupportedOperationException:"); in = ssocket.getInputStream(); try { out = ssocket.getOutputStream(); } catch (UnsupportedOperationException e) { System.out.println("UnsupportedOperationException has been " + "thrown as expected."); } in.read(b); System.out.println("Text received: \"" + new String(b) + "\""); ssocket.close(); ssocket.unlink(); } } 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 unix-socket.md;categories 改为 Java 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 26266-08-26 · Updated 9096-10-09 · 2 min · 323 words · -

LinkedTransferQueue

LinkedTransferQueue LinkedTransferQueue是在JDK1.7时,J.U.C包新增的一种比较特殊的阻塞队列,它除了具备阻塞队列的常用功能外,还有一个比较特殊的transfer方法。 我们知道,在普通阻塞队列中,当队列为空时,消费者线程(调用take或poll方法的线程)一般会阻塞等待生产者线程往队列中存入元素。而LinkedTransferQueue的transfer方法则比较特殊: 当有消费者线程阻塞等待时,调用transfer方法的生产者线程不会将元素存入队列,而是直接将元素传递给消费者; 如果调用transfer方法的生产者线程发现没有正在等待的消费者线程,则会将元素入队,然后会阻塞等待,直到有一个消费者线程来获取该元素。 有一篇论文讨论了其算法与性能: 地址: http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf LinkedTransferQueue 实现了一个重要的接口 TransferQueue, 该接口含有下面几个重要方法: 1. transfer(E e) 若当前存在一个正在等待获取的消费者线程,即立刻移交之;否则,会插入当前元素e到队列尾部,并且等待进入阻塞状态,到有消费者线程取走该元素。 2. tryTransfer(E e) 若当前存在一个正在等待获取的消费者线程 (使用take()或者poll()函数) ,使用该方法会即刻转移/传输对象元素e; 若不存在,则返回false,并且不进入队列。这是一个不阻塞的操作。 3. tryTransfer(E e, long timeout, TimeUnit unit) 若当前存在一个正在等待获取的消费者线程,会立即传输给它; 否则将插入元素e到队列尾部,并且等待被消费者线程获取消费掉, 若在指定的时间内元素e无法被消费者线程获取,则返回false,同时该元素被移除。 4. hasWaitingConsumer() 判断是否存在消费者线程 5. getWaitingConsumerCount() 获取所有等待获取元素的消费线程数量 其实transfer方法在SynchronousQueue的实现中就已存在了,只是没有做为API暴露出来。SynchronousQueue有一个特性:它本身不存在容量,只能进行线程之间的 元素传送。SynchronousQueue在执行offer操作时,如果没有其他线程执行poll,则直接返回false.线程之间元素传送正是通过transfer方法完成的。 有一个使用案例,我们知道ThreadPoolExecutor调节线程的原则是: 先调整到最小线程,最小线程用完后,他会将优先将任务放入缓存队列(offer(task)),等缓冲队列用完了,才会向最大线程数调节。这似乎与我们所理解的线程池模型有点不同。我们一般采用增加到最大线程后,才会放入缓冲队列中,以达到最大性能。ThreadPoolExecutor代码片段: public void execute(Runnable command) { if (command == null) throw new NullPointerException(); if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) { if (runState == RUNNING && workQueue.offer(command)) { if (runState != RUNNING || poolSize == 0) ensureQueuedTaskHandled(command); } else if (!addIfUnderMaximumPoolSize(command)) reject(command); // is shutdown or saturated } } 如果我们采用SynchronousQueue作为ThreadPoolExecuto的缓冲队列时,在没有线程执行poll时(即存在等待线程),则workQueue.offer(command)返回false,这时ThreadPoolExecutor就会增加线程,最快地达到最大线程数。但也仅此而已,也因为SynchronousQueue本身不存在容量,也决定了我们一般无法采用SynchronousQueue作为ThreadPoolExecutor的缓存队列。而一般采用LinkedBlockingQueue的offer方法来实现。最新的LinkedTransferQueue也许可以帮我们解决这个问题,后面再说。 ...

Created 14146-09-14 · Updated 9096-10-09 · 1 min · 187 words · -

LinkedBlockingQueue

LinkedBlockingQueue 基于链表的阻塞队列,同 ArrayBlockingQueue 类似,其内部也维持着一个数据缓冲队列 (该队列是一个链表) ,生产者存入的数据会缓存在队列内部,生产者立即返回;只有当队列缓冲区达到最大值缓存容量时 (LinkedBlockingQueue 可以通过构造函数指定该值) ,才会阻塞生产者队列,直到消费者从队列中消费掉一份数据,生产者线程会被唤醒,反之对于消费者这端的处理也基于同样的原理。而LinkedBlockingQueue 之所以能够高效的处理并发数据,还因为其对于生产者端和消费者端 分别采用了独立的锁 来控制数据同步,这也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。 作为开发者,我们需要注意的是,如果构造一个 LinkedBlockingQueue 对象,而没有指定其容量大小,LinkedBlockingQueue 会默认一个类似无限大小的容量 (Integer.MAX_VALUE) ,这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。 此队列按 FIFO (先进先出) 排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。 新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列, 但是在大多数并发应用程序中,其可预知的性能要低。 可选的容量范围构造方法参数作为防止队列过度扩展的一种方法。 如果未指定容量,默认容量为 Integer.MAX_VALUE ,容量范围可以在构造方法参数中指定作为防止队列过度扩展。 此对象是线程阻塞-线程安全的 不接受 null 元素 它实现了BlockingQueue接口。 实现了 Collection 和 Iterator 接口的所有可选方法。 在JDK5/6中,LinkedBlockingQueue和ArrayBlocingQueue等对象的poll(long timeout, TimeUnit unit)存在内存泄露Leak的对象AbstractQueuedSynchronizer.Node,据称JDK5会在Update12里Fix,JDK6会在Update2里Fix 下面介绍几种常用的方法: 定义一个输出方法: static void v(Object s){System.out.println(s.toString());} LinkedBlockingQueue<String> bq=new LinkedBlockingQueue<String>(); for(int i=0;i<100;i++) { bq.add("i"+i);//如果空间已满,此方法会抛出异常,所以这就是put,或者offer方法的优势所在 } String s1=bq.take();//i0 String s2=bq.take();//i1 bq.offer("ix",5,TimeUnit.SECONDS);//在尾部插入一个元素,如果有必要 ,等待 指定的时间,使得队列变得可用。返回boolean值 表示是否插入成功。 bq.put("ixx");//将指定的元素添加到队列的尾部,如有必要,则等待空间变得可用,如果空间满了,则会一直等到空间可用时,进行插入。 bq.poll();//poll() //poll(long timeout, TimeUnit unit) 检索并移除此队列的头,如果此队列为空,则返回 null。 bq.clear() 从队列彻底移除所有元素。 ...

Created 14146-09-14 · Updated 9096-10-09 · 3 min · 452 words · -

jmap

jmap 、基本参数: -dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. -finalizerinfo 打印正等候回收的对象的信息. -heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况. -histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀"*". 如果live子参数加上后,只统计活的对象数量. -permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. -F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. -h | -help 打印辅助信息 -J 传递参数给jmap启动的jvm. pid 需要被打印配相信息的java进程id,创业与打工的区别 - 博文预览,可以用jps查问. 4、使用示例 1)、[fenglb@ccbu-156-5 ~]$ jmap -histo 4939 sudo ./jmap -dump:format=b,file=/tmp/917dump.dat 8949 If you take a look at the source code for com.sun.tools.hat.internal.parser.Reader, you'll see that it's looking for the magic number 0x4a415641. This value is used to help identify valid heap dump files. jmap should append this value as the first four bytes of any heap dump file it creates. http://stackoverflow.com/questions/15507047/jhat-throwing-unrecognized-magic-number http://blog.csdn.net/gtuu0123/article/details/6039474 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;categories 改为 Java 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 17176-09-17 · Updated 9096-10-09 · 1 min · 111 words · -

float double NaN

float double NaN http://zranye.iteye.com/blog/1344880 http://blog.csdn.net/naruto_ahu/article/details/8805808 (注意,double中的NaN类似) 在帮助文档中,NaN是这样解释的 (double的,和float差不多) : public static final double NaN 保存 double 类型的 NaN 值的常量。它等于 Double.longBitsToDouble(0x7ff8000000000000L) 返回的值。 我是这样解释的 (理解不深,有错请不吝赐教) : NaN-Not-a-Number,其实是指一个不合理的实数,在合法却不合理的情况下避免你的程序出现Exception。 NaN什么也不是,如果理解成一个超越了float范围的常量 (或者double) ,那也是不对的,为什么?试试判断 (NaN==NaN) 吧,你会发现这返回了一个false。这在java底层是怎么做到的呢?最直接的方式是看java源代码咯。 /** A constant holding a Not-a-Number (NaN) value of type float. It is equivalent to the value returned by Float.intBitsToFloat(0x7fc00000). */ public static final float NaN = 0.0f / 0.0f; 上面这一段,就是floa的NaN定义了。这并不是一个超出了范围的常量,而是java的Float中人为得制造出来的一个合法但是不合理的实数了 (看来那位仁兄说得基本都对了) 。所以,NaN==NaN永远等于false啦。 那用什么来判断是否合理的Number呢?很奇怪的是,java提供了一个isNaN()的方法,指是否是一个不合理的实数。是否很拗口?我在javascript中第一次接触这个东西,也觉得很奇怪。 为什么有这样一个判断的方法不把NaN设置成private的,却又对外开放?难道担心我们不能主动制造一个不合理的实数出来?本人菜鸟,如果有高手能解答,还请不吝赐教,理解未深,有错误请指出,谢谢。 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;categories 改为 Java 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 4046-12-04 · Updated 9096-10-09 · 1 min · 83 words · -

Java Unix Socket 2

java unix socket <dependency> <groupId>uk.co.caprica</groupId> juds</artifactId> <version>0.94.1</version> </dependency> 维护记录 时间 修改内容 原因 2026-10-09 修复本地 Hugo 构建的 Raw HTML 警告:代码/配置放入代码块,正文中的尖括号占位符改为行内代码;文件重命名为 unix-socket-2.md;title 改为「Java Unix Socket 2」;categories 改为 Java 正文中的 HTML/XML 片段被当作原始 HTML 丢弃;文件名/URL/标题按规范调整

Created 29296-02-29 · Updated 9096-10-09 · 1 min · 31 words · -

Java 数组合并

java 数组 合并 http://blog.csdn.net/jaycee110905/article/details/9179227 Java中如何把两个数组合并为一个 标签: JavaArray合并数组 2013-06-26 14:54 22185人阅读 评论(1) 收藏 举报 分类: JAVA (39) 目录(?)[+] http://freewind.me/blog/20110922/350.html 在Java中,如何把两个String[]合并为一个? 看起来是一个很简单的问题。但是如何才能把代码写得高效简洁,却还是值得思考的。这里介绍四种方法,请参考选用。 一、apache-commons 这是最简单的办法。在apache-commons中,有一个ArrayUtils.addAll(Object[], Object[])方法,可以让我们一行搞定: String[] both = (String[]) ArrayUtils.addAll(first, second); 其它的都需要自己调用jdk中提供的方法,包装一下。 为了方便,我将定义一个工具方法concat,可以把两个数组合并在一起: static String[] concat(String[] first, String[] second) {} 为了通用,在可能的情况下,我将使用泛型来定义,这样不仅String[]可以使用,其它类型的数组也可以使用: static <T> T[] concat(T[] first, T[] second) {} 当然如果你的jdk不支持泛型,或者用不上,你可以手动把T换成String。 二、System.arraycopy() static String[] concat(String[] a, String[] b) { String[] c= new String[a.length+b.length]; System.arraycopy(a, 0, c, 0, a.length); System.arraycopy(b, 0, c, a.length, b.length); return c; } 使用如下: ...

Created 25256-03-25 · Updated 9096-10-09 · 2 min · 255 words · -

NMT, Native Memory Tracking

NMT, Native Memory Tracking NMT for Hotspot VM is turned off by default. Turn this feature on using JVM command line option -XX:NativeMemoryTracking=[off | summary | detail] 注意,根据Java官方文档,开启NMT会有5%-10%的性能损耗; 访问NMT数据 JDK提供了jcmd命令来访问NMT数据: jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB] 配置项 说明 summary 只打印打印按分类汇总的内存 detail 打印按分类汇总的内存用法、virtual memory map和每次内存分配调用 baseline 创建内存快照,以比较不同时间的内存差异 summary.diff 打印自上次baseline到现在的内存差异,显示汇总信息 detail.diff 打印自上次baseline到现在的内存差异, 显示详细信息 shutdown 关闭NMT功能,NMT can be shutdown using jcmd utility, but can not start/restart using jcmd ...

Created 6066-02-06 · Updated 9096-10-09 · 1 min · 110 words · -

ThreadLocal

ThreadLocal ThreadLocal 是什么 弱引用 避免内存溢出的操作 开放地址法解决 hash 冲突 各种内部类 线程本地变量有时会简写为 TLV, Thread Local Variables ThreadLocal 是什么 ThreadLocal 是线程的局部变量, 也就是说这个变量是线程独有的。 通常情况下, 我们创建的变量是可以被任何一个线程访问并修改的。而使用 ThreadLocal 创建的变量只能被当前线程访问, 其他线程则无法访问和修改。 变量是同一个, 但是每个线程都使用同一个初始值, 也就是使用同一个变量的一个新的副本, 这种情况下 TreadLocal 就非常有用。 应用场景: 当很多线程需要多次使用同一个对象, 并且需要该对象具有相同初始值的时候, 最适合使用TreadLocal。 事实上,从本质上讲,就是每个线程都维持一个 MAP,而这个map的key就是TreadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那就肯定不存在线程安全的问题。总体来讲,TreadLocal这个变量的状态根本没有发生变化。它仅仅是充当了一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮助我们做了这个事情。 使用TreadLocal维护变量时, TreadLocal为每个使用该变量的线程提供独立地变量副本, 所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。从线程的角度看,目标变量对象是线程的本地变量,这也是类名中Local所需要表达的意思。 TreadLocal的四个方法 void set(Object val),设置当前线程的线程局部变量的值 Object get () 返回当前线程所对用的线程局部变量。 void remove() 将当前线程局部变量的值删除,目的是为了减少内存的占用,线程结束后,局部变量自动被GC Object initValue() 返回该线程局部变量的初始值,使用protected修饰,显然是为了让子类覆盖而设计的。 ThreadLocalMap HashMap 的数据结构是数组+链表 ThreadLocalMap的数据结构仅仅是数组 HashMap 是通过链地址法解决 hash 冲突的问题 ThreadLocalMap 是通过开放地址法来解决 hash 冲突的问题 HashMap 里面的Entry 内部类的引用都是强引用 ThreadLocalMap里面的Entry 内部类中的key 是弱引用,value 是强引用 对象存放在哪里 在Java中, 栈内存归属于单个线程, 每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。 ...

Created 24246-03-24 · Updated 9096-10-09 · 3 min · 619 words · -

Guava cache

Guava cache http://www.cnblogs.com/peida/p/Guava_Cache.html 缓存,在我们日常开发中是必不可少的一种解决性能问题的方法。简单的说,cache 就是为了提升系统性能而开辟的一块内存空间。 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用。在日常开发的很多场合,由于受限于硬盘IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的逻辑处理会导致硬盘和CPU资源的瓶颈出现。缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同的数据资源时,直接从缓存的内存块中返回数据,这样不但可以提高系统的响应时间,同时也可以节省对这些数据的处理流程的资源消耗,整体上来说,系统性能会有大大的提升。 缓存在很多系统和架构中都用广泛的应用,例如: 1.CPU缓存 2.操作系统缓存 3.本地缓存 4.分布式缓存 5.HTTP缓存 6.数据库缓存 等等,可以说在计算机和网络领域,缓存无处不在。可以这么说,只要有硬件性能不对等,涉及到网络传输的地方都会有缓存的身影。 Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好。 Guava Cache有两种创建方式: cacheLoader callable callback 通过这两种方法创建的cache,和通常用map来缓存的做法比,不同在于,这两种方法都实现了一种逻辑——从缓存中取key X的值,如果该值已经缓存过了,则返回缓存中的值,如果没有缓存过,可以通过某个方法来获取这个值。但不同的在于cacheloader的定义比较宽泛,是针对整个cache定义的,可以认为是统一的根据key值load value的方法。而callable的方式较为灵活,允许你在get的时候指定。 cacheLoader方式实现实例: @Test public void TestLoadingCache() throws Exception{ LoadingCache<String,String> cahceBuilder=CacheBuilder .newBuilder() .build(new CacheLoader<String, String>(){ @Override public String load(String key) throws Exception { String strProValue="hello "+key+"!"; return strProValue; } }); System.out.println("jerry value:"+cahceBuilder.apply("jerry")); System.out.println("jerry value:"+cahceBuilder.get("jerry")); System.out.println("peida value:"+cahceBuilder.get("peida")); System.out.println("peida value:"+cahceBuilder.apply("peida")); System.out.println("lisa value:"+cahceBuilder.apply("lisa")); cahceBuilder.put("harry", "ssdded"); System.out.println("harry value:"+cahceBuilder.get("harry")); } 输出: ...

Created 31316-03-31 · Updated 9096-10-09 · 3 min · 496 words · -

Java jps

java jps jps位于jdk的bin目录下,其作用是显示当前系统的java进程情况,及其id号。 jps相当于Solaris进程工具ps。不象"pgrep java"或"ps -ef grep java",jps并不使用应用程序名来查找JVM实例。因此,它查找所有的Java应用程序,包括即使没有使用java执行体的那种 (例如,定制的启动 器) 。另外,jps仅查找当前用户的Java进程,而不是当前系统中的所有进程。 -h: help -l: 输出应用程序main class的完整package名 或者 应用程序的jar文件完整路径名 -m: 输出传递给main 方法的参数,在嵌入式jvm上可能是null, 在这里,在启动main方法的时候,我给String[] args传递两个参数。hollis,chuang,执行jsp -m: -v: 输出传递给JVM的参数 在这里,在启动main方法的时候,我给jvm传递一个参数: -Dfile.encoding=UTF-8,执行jps -v: 位置 我们知道,很多Java命令都在jdk的JAVA_HOME/bin/目录下面,jps也不例外,他就在bin目录下,所以,他是java自带的一个命令。 功能 jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情况。 原理 jdk中的jps命令可以显示当前运行的java进程以及相关参数,它的实现机制如下: java程序在启动以后,会在java.io.tmpdir指定的目录下,就是临时文件夹里,生成一个类似于hsperfdata_User的文件夹,这个文件夹里 (在Linux中为/tmp/hsperfdata_{userName}/) ,有几个文件,名字就是java进程的pid,因此列出当前运行的java进程,只是把这个目录里的文件名列一下而已。 至于系统的参数什么,就可以解析这几个文件获得。 hollis@hos:/tmp/hsperfdata_hollis$ pwd /tmp/hsperfdata_hollis hollis@hos:/tmp/hsperfdata_hollis$ ll total 48 drwxr-xr-x 2 hollis hollis 4096 4月 16 10:54 ./ drwxrwxrwt 7 root root 12288 4月 16 10:56 ../ ...

Created 5056-05-05 · Updated 9096-10-09 · 2 min · 243 words · -

On-Heap and Off-Heap Memory 堆内内存, 堆外内存

堆内内存, 堆外内存 一、什么是堆外内存 堆内内存 (on-heap memory) 回顾 堆外内存和堆内内存是相对的二个概念,其中堆内内存是我们平常工作中接触比较多的,我们在jvm参数中只要使用-Xms,-Xmx等参数就可以设置堆的大小和最大值,理解jvm的堆还需要知道下面这个公式: 堆内内存 = 新生代+老年代+持久代 如下面的图所示: Paste_Image.png 在使用堆内内存 (on-heap memory) 的时候,完全遵守JVM虚拟机的内存管理机制,采用垃圾回收器 (GC) 统一进行内存管理,GC会在某些特定的时间点进行一次彻底回收,也就是Full GC,GC会对所有分配的堆内内存进行扫描,在这个过程中会对JAVA应用程序的性能造成一定影响,还可能会产生Stop The World。 常见的垃圾回收算法主要有: 引用计数器法 (Reference Counting) 标记清除法 (Mark-Sweep) 复制算法 (Coping) 标记压缩法 (Mark-Compact) 分代算法 (Generational Collecting) 分区算法 (Region) 注: 在这里我们不对各个算法进行深入介绍,感兴趣的同学可以关注我的下一篇关于垃圾回收算法的介绍分享。 堆外内存 (off-heap memory) 介绍 和堆内内存相对应,堆外内存就是把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理 (而不是虚拟机) ,这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。 作为JAVA开发者我们经常用java.nio.DirectByteBuffer对象进行堆外内存的管理和使用,它会在对象创建的时候就分配堆外内存。 DirectByteBuffer类是在Java Heap外分配内存,对堆外内存的申请主要是通过成员变量unsafe来操作,下面介绍构造方法 DirectByteBuffer(int cap) { super(-1, 0, cap, cap); //内存是否按页分配对齐 boolean pa = VM.isDirectMemoryPageAligned(); //获取每页内存大小 int ps = Bits.pageSize(); //分配内存的大小,如果是按页对齐方式,需要再加一页内存的容量 long size = Math.max(1L, (long)cap + (pa ? ps : 0)); //用Bits类保存总分配内存(按页分配)的大小和实际内存的大小 Bits.reserveMemory(size, cap); long base = 0; try { //在堆外内存的基地址,指定内存大小 base = unsafe.allocateMemory(size); } catch (OutOfMemoryError x) { Bits.unreserveMemory(size, cap); throw x; } unsafe.setMemory(base, size, (byte) 0); //计算堆外内存的基地址 if (pa && (base % ps != 0)) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); att = null; } 注: 在Cleaner 内部中通过一个列表,维护了一个针对每一个 directBuffer 的一个回收堆外内存的 线程对象(Runnable),回收操作是发生在 Cleaner 的 clean() 方法中。 ...

Created 17176-05-17 · Updated 9096-10-09 · 3 min · 500 words · -

ForkJoin

ForkJoin ForkJoinPool 适合执行计算密集型且可进行拆分任务并汇总结果(类似MapReduce)的任务,执行这种任务可以充分利用多核处理器优势提高任务处理速度,实际上 ForkJoinPool 内部的工作窃取队列的高性能 (远高于普通线程池的BlockingQueue) 也决定其适用于执行大量的简短的小任务。 ———————————————— 版权声明:本文为CSDN博主「heng_zou」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/heng_zou/article/details/118193846 什么是 Fork/Join 框架 Fork/Join 框架是 Java7 提供的一个用于并行执行任务的框架(Fork/Join Framework), 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过 Fork 和 Join 这两个单词来理解下 Fork/Join 框架,Fork 就是把一个大任务切分为若干子任务并行的执行,Join 就是合并这些子任务的执行结果,最后得到这个大任务的结果。比如计算 1+ 2+… + 10000,可以分割成 10 个子任务,每个子任务分别对 1000 个数进行求和,最终汇总这 10 个子任务的结果。 ForkJoinPool http://blog.dyngr.com/blog/2016/09/15/java-forkjoinpool-internals/ ForkJoinPool 不是为了替代 ExecutorService, 而是它的补充, 在某些应用场景下性能比 ExecutorService 更好。 (见 Java Tip: When to use ForkJoinPool vs ExecutorService ) https://www.infoworld.com/article/2078440/java-tip-when-to-use-forkjoinpool-vs-executorservice.html ForkJoinPool 主要用于实现"分而治之"的算法, 特别是分治之后递归调用的函数, 例如 quick sort 等。 [[quick-sort]] ForkJoinPool 最适合的是计算密集型的任务, 如果存在 I/O, 线程间同步, sleep() 等会造成线程长时间阻塞的情况时, 最好配合使用 ManagedBlocker ...

Created 22226-06-22 · Updated 9096-10-09 · 4 min · 744 words · -

Java 7 Phaser

‘Java 7 Phaser’ http://www.oschina.net/question/12_35433 Java 7 引入了一个全新灵活的线程同步机制,名为 Phaser 。 如果你需要等待线程结束然后继续执行其他任务,那么 Phaser 是一个好的选择,接下来我们一步步来介绍 Phaser 的使用: 首先看下面的代码: import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Phaser; public class PhaserExample { public static void main(String[] args) throws InterruptedException { List<Runnable> tasks = new ArrayList<>(); for (int i = 0; i < 2; i++) { Runnable runnable = new Runnable() { @Override public void run() { int a = 0, b = 1; for (int i = 0; i < 2000000000; i++) { a = a + b; b = a - b; } } }; tasks.add(runnable); } new PhaserExample().runTasks(tasks); } void runTasks(List<Runnable> tasks) throws InterruptedException { final Phaser phaser = new Phaser(1) { protected boolean onAdvance(int phase, int registeredParties) { return phase >= 1 || registeredParties == 0; } }; for (final Runnable task : tasks) { phaser.register(); new Thread() { public void run() { do { phaser.arriveAndAwaitAdvance(); task.run(); } while (!phaser.isTerminated()); } }.start(); Thread.sleep(500); } phaser.arriveAndDeregister(); } } 这个例子让我们可以深入了解 Phaser 的使用,下面是对这个代码的分析: ...

Created 27276-09-27 · Updated 9096-10-09 · 4 min · 807 words · -

Guava Multimap

Guava Multimap 在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业务逻辑处理。例如: import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; public class MultimapTest { Map<String, List<StudentScore>> StudentScoreMap = new HashMap<String, List<StudentScore>>(); @Test public void testStudentScore(){ for(int i=10;i<20;i++){ StudentScore studentScore=new StudentScore(); studentScore.CourseId=1001+i; studentScore.score=100-i; addStudentScore("peida",studentScore); } System.out.println("StudentScoreMap:"+StudentScoreMap.size()); System.out.println("StudentScoreMap:"+StudentScoreMap.containsKey("peida")); System.out.println("StudentScoreMap:"+StudentScoreMap.containsKey("jerry")); System.out.println("StudentScoreMap:"+StudentScoreMap.size()); System.out.println("StudentScoreMap:"+StudentScoreMap.get("peida").size()); List<StudentScore> StudentScoreList=StudentScoreMap.get("peida"); if(StudentScoreList!=null&&StudentScoreList.size()>0){ for(StudentScore stuScore:StudentScoreList){ System.out.println("stuScore one:"+stuScore.CourseId+" score:"+stuScore.score); } } } public void addStudentScore(final String stuName,final StudentScore studentScore) { List<StudentScore> stuScore = StudentScoreMap.get(stuName); if (stuScore == null) { stuScore = new ArrayList<StudentScore>(); StudentScoreMap.put(stuName, stuScore); } stuScore.add(studentScore); } } class StudentScore{ int CourseId; int score; } 说明: 想 Map<String, List<StudentScore>> StudentScoreMap = new HashMap<String, List<StudentScore>>()这样的数据结构,自己实现起来太麻烦,你需要检查key是否存在,不存在时则创建一个,存在时在List后面添加上一个。这个过程是比较痛苦的,如果你希望检查List中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么则需要更多的代码来实现。 ...

Created 18186-10-18 · Updated 9096-10-09 · 2 min · 287 words · -

ConcurrentLinkedDeque

ConcurrentLinkedDeque 非阻塞线程安全列表——ConcurrentLinkedDeque应用举例 在java中,最常用的数据结构可能是列表。有数目不详的元素列表,你可以添加、阅读、或删除任何位置的元素。此外,并发列表允许不同的线程列表中添加或删除元素时不产生任何数据不一致。非阻塞列表提供如下操作,如果操作不能立即完成,列出抛出异常或者返回一个null值。Java 7中引入了ConcurrentLinkedDeque类,它实现了一个非阻塞并发列表,在本教程中,我们将学习使用这个类。 在这个例子中,我们将实现一个示例使用以下两个不同的任务: 一个将大量数据添加到一个列表中 一个大量地从同样的列表中删除数据 让我们为每个任务创建的线程: package com.howtodoinjava.demo.multithreading.concurrentLinkedDequeExample; import java.util.concurrent.ConcurrentLinkedDeque; public class AddTask implements Runnable { private ConcurrentLinkedDeque<String> list; public AddTask(ConcurrentLinkedDeque<String> list) { this.list = list; } @Override public void run() { String name = Thread.currentThread().getName(); for (int i = 0; i < 10000; i++) { list.add(name + ": Element " + i); } } } 和: ...

Created 23236-10-23 · Updated 9096-10-09 · 2 min · 306 words · -

Unsafe

“Unsafe” Unsafe在sun.misc 下,顾名思义,这是一个不安全的类,因为Unsafe类所操作的并不属于Java标准,Java的一系列内存操作都是交给jvm的,而Unsafe类却能有像C语言的指针一样直接操作内存的能力,同时也会带来了指针的问题。过度使用Unsafe类的话,会使出错率变得更大,因此官方才命名为Unsafe,并且不建议使用,连注释的没有。 而为了安全使用Unsafe,Unsafe类只允许jdk自带的类使用,从下面的代码中可以看出 public static Unsafe getUnsafe() { Class<?> caller = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } 如果当前Class是非系统加载的(也就是caller.getClassLoader()不为空),直接抛出SecurityException 。 在java9之后,又出现了一个jdk.internal.misc.Unsafe类,其功能与sun.misc.Unsafe类是一样的,唯一不一样的是在 getSafe() 的时候,jdk.internal.misc.Unsafe是没有做校验的,但是jdk包下的代码,应用开发时是不能直接调用的,而且在java9之后,两个Unsafe类都有充足的注释。 JUC紧密使用了Unsafe的功能。 功能简介 Unsafe类的功能主要分为内存操作、CAS、Class相关、对象操作、数组相关、内存屏障、系统相关、线程调度等功能。 内存操作 堆外(native memory)内存操作 //分配内存,并返回内存地址 public native long allocateMemory(long bytes); //扩充内存,address可以是allocateMemory方法返回的地址,bytes是扩充的大小 public native long reallocateMemory(long address, long bytes); //释放内存 public native void freeMemory(long address); //在给定的内存块设置默认值 public native void setMemory(long address, long bytes, byte value); //获取指定地址值的byte类型 public native byte getByte(long address); //设置堆外指定值的byte类型的值 public native void putByte(long address, byte x); 堆内内存操作 ...

Created 20206-09-20 · Updated 9096-10-09 · 3 min · 456 words · -