
public class Client { public Data request(final String queryStr){ final FutureData future=new FutureData(); new Thread(){ public void run(){ RealData realData=new RealData(queryStr); future.setRealData(realData); } }.start(); return future; }}public interface Data { String getResult();}public class FutureData implements Data { //FutureData是RealData的包装 protected RealData realData=null; protected boolean isReady=false; public synchronized void setRealData(RealData realData){ if(isReady) return; this.realData=realData; isReady=true; notifyAll(); } @Override public synchronized String getResult() { while (!isReady){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } return realData.result; }}public class RealData implements Data { protected final String result; public RealData(String para){ //RealData的构造很慢 StringBuffer sb=new StringBuffer(); for (int i=0;i<10;i++){ sb.append(para); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } result=sb.toString(); } @Override public String getResult() { return result; }}Master-Worker 的好处是可以将大任务分为若干个小任务,并行执行。
public class Master { //任务队列 protected Queue<Object> workQueue=new ConcurrentLinkedQueue<>(); //Woker线程队列 protected Map<String,Thread> threadMap=new HashMap<>(); //子任务的结果集 protected Map<String,Object> resultMap=new ConcurrentHashMap<>(); //是否所有子任务都结束了 public boolean isComplete(){ for (Map.Entry<String,Thread> entry:threadMap.entrySet()){ if(entry.getValue().getState()!=Thread.State.TERMINATED){ return false; } } return true; } public Master(Worker worker,int countWorker){ worker.setWorkQueue(workQueue); worker.setResultMap(resultMap); for (int i = 0; i <countWorker ; i++) { threadMap.put(Integer.toString(i),new Thread(worker,Integer.toString(i))); } } //提交一个任务 public void submit(Object object){ workQueue.add(object); } //返回子任务结果集 public Map<String,Object> getResultMap(){ return resultMap; } //开始运行所有的Worker进程 public void execute(){ for (Map.Entry<String,Thread> entry:threadMap.entrySet()){ entry.getValue().start(); } }}public class Worker implements Runnable { //任务队列,用于取得子任务 protected Queue<Object> workQueue; //子任务处理结果集 protected Map<String,Object> resultMap; public void setWorkQueue(Queue<Object> workQueue) { this.workQueue = workQueue; } //子任务的处理逻辑,在子类中具体实现 public Object handle(Object input){ return input; } public void setResultMap(Map<String, Object> resultMap) { this.resultMap = resultMap; } @Override public void run() { while (true){ Object input=workQueue.poll(); if(input==null)break; Object result=handle(input); resultMap.put(Integer.toString(input.hashCode()),result); } }}public class PlusWorker extends Worker { @Override public Object handle(Object input) { if(input instanceof Integer){ Integer i=(Integer)input; return i*i*i; } return 0; }}测试代码:
@Test public void test26(){ long start=System.currentTimeMillis(); Master master=new Master(new PlusWorker(),5); for (int i = 0; i <100 ; i++) { master.submit(i); } master.execute(); long re=0; Map<String,Object> resultMap=master.getResultMap(); while (resultMap.size()>0||!master.isComplete()){ Set<String> keys = resultMap.keySet(); String key=null; for (String k:keys){ key=k; break; } Integer i=null; if(key!=null) i=(Integer)resultMap.get(key); if(i!=null) re+=i; if(key!=null) resultMap.remove(key); } System.out.println(re); System.out.println(System.currentTimeMillis()-start); }Ncpu:CPU 的数量
Ucpu:目标 Cpu 的使用率 0<=Ucpu<=1
W/C:等待时间和计算时间的比率
最优线程池大小为:
Nthreads=NcpuUcpu(1+W/C);
ThreadPoolExecutor 是一个可以扩展的线程池,它提供了 beforeExecutor()和 afterExecutor()和 terminated()3 个方法进行扩展。
public class LockTest { private static final int CIRCLE=20000000; public static void main(String[] args) { long start=System.currentTimeMillis(); for (int i = 0; i <CIRCLE ; i++) { createStringBuffer("java","Performance"); } long bufferCost=System.currentTimeMillis()-start; System.out.println("CreateStringBuffer:"+bufferCost+"ms"); } public static String createStringBuffer(String s1,String s2){ StringBuffer sb=new StringBuffer(); sb.append(s1); sb.append(s2); return sb.toString(); }}/** * Amino框架实现了Master-woker模式 */public class Pow3 implements Doable<Integer,Integer> { //业务逻辑 @Override public Integer run(Integer integer) { return integer*integer*integer; } public static void main(String[] args) { MasterWorker<Integer,Integer> mw=MasterWorkerFactory.newStatic(new Pow3()); List<MasterWorker.ResultKey> keyList=new Vector<>(); for (int i = 0; i <100 ; i++) { keyList.add(mw.submit(i)); } mw.execute(); int re=0; while (keyList.size()>0){ MasterWorker.ResultKey k=keyList.get(0); Integer i=mw.result(k); if(i!=null){ re+=i; keyList.remove(0); } } System.out.println(re); }}为了增加系统的并发性,人们提出了线程,随着应用程序日趋复杂,并发量要求越来越高,线程也变得沉重了起来。为了使系统有更高的并行度,便有了协程的概念。如果说线程是轻量级进程,那么协程就是轻量级的线程。
相关框架:kilim。
介绍:略。

1、程序计数器
每一个线程都有一个独立的程序计数器,用于记录下一条要执行的指令,各个线程互不影响。
2、Java 虚拟机栈
它和 Java 线程在同一时间创建,保存方法的局部变量,部分结果,并参与方法的调用和返回。

public void test28(){ //gc无法回收,因为b还在局部变量表中 { byte[] b=new byte[6*1024*1024]; } System.gc(); System.out.println("first explict gc over"); } public void test29(){ //gc可以回收,因为变量a复用了b的字 { byte[] b=new byte[6*1024*1024]; } int a=0; System.gc(); System.out.println("first explict gc over"); }3、本地方法栈
本地方法栈和 java 虚拟机栈的功能很像,本地方法栈用于管理本地方法的调用。
4、Java 堆
几乎所有的对象和数组都是在堆中分配空间的。

5、方法区
主要保存类的元数据,所有线程共享的。其中最为重要的是类的类型信息,常量池,静态变量,域信息,方法信息。在 Hot Spot 虚拟机中,方法区也被称为永久区。

1、引用计数法
如果有引用,计数器就加 1,当引用失效时,计数器就减 1.这种方法无法处理循环引用,不适用与 JVM 的回收。
2、标记-清除算法
第一阶段,标记所有从根节点开始可达的对象。第二阶段,清理所有未标记的对象。缺点是回收后的空间是不连续的。
3、复制算法
将原有的空间分为两块,将正在使用的那个空间的活对象复制到未使用的那个空间,在垃圾回收时,只需要清理正在使用的内存空间的所有对象,然后交换两个内存空间的角色。缺点是要将系统内存折半。
4、标记压缩算法
标记完成之后,将所有的存活对象压缩到内存的一端,然后清除边界外所有的空间。避免了碎片的产生。
5、增量算法
一次性的垃圾清理会造成系统长时间停顿,那么就可以让垃圾收集线程和应用程序线程交替执行。在垃圾回收的过程中间断性的执行应用程序代码。
6、分代
对新生代使用复制算法,老年代使用标记-压缩算法。
7、串行收集器
8、CMS 收集器
使用的是标记清除算法,并行的垃圾收集器
9、G1 收集器
基于标记-压缩算法,目标是一款服务器的收集器,在吞吐量和停顿控制上,要优于 CMS 收集器。
观察 GC 情况:
package com.mmc.concurrentcystudy.test;import java.util.HashMap;public class StopWorldTest { public static class MyThread extends Thread{ HashMap map=new HashMap(); @Override public void run() { try{ while (true){ if(map.size()*512/1024/1024>=400){ //防止内存溢出 map.clear(); System.out.println("clean map"); } byte[] b1; for (int i = 0; i <100 ; i++) { b1=new byte[512]; //模拟内存占用 map.put(System.nanoTime(),b1); } Thread.sleep(1); } }catch (Exception e){} } } public static class PrintThread extends Thread{ //每毫秒打印时间信息 public static final long starttime=System.currentTimeMillis(); @Override public void run() { try{ while (true){ long t=System.currentTimeMillis()-starttime; System.out.println(t/1000+"."+t%1000); Thread.sleep(100); } }catch (Exception e){} } } public static void main(String[] args) { MyThread t=new MyThread(); PrintThread p=new PrintThread(); t.start(); p.start(); }}1、将新对象预留在新生代
避免新对象因空间不够进入了年老代,可以适当增加新生代的 from 大小。
2、大对象直接进入老年代
在大部分情况下,新对象分配在新生代是合理的,但是,对于大对象,很可能扰乱新生代,使得大量小的新生代对象因空间不足移到老年代。
3、设置对象进入老年代的年龄
4、稳定与震荡的堆大小
1、一般来说稳定的堆大小是对回收有利的,获得一个稳定的堆大小的方法就是设置-Xms 和-Xmx 的大小一致。稳定的堆空间可以减少 GC 的次数,但是会增加每次 GC 的时间。
基于这样的考虑,JVM 提供了压缩和扩展堆空间的参数。
5、吞吐量优先案例
在拥有 4G 内存和 32 核 CPU 的计算机上,进行吞吐量的优化

6、使用大页案例
在 Solaris 系统中,可以支持大页的使用,大的内存分页可以增强 CPU 的内存寻址能力。
7、降低停顿案例
为了降低停顿,应尽可能将对象预留在新生代,因为新生代的 GC 成本远小于老年代。

1、JIT 编译参数
JIT 编译器可以将字节代码编译成本地代码,从而提高执行效率。
2、堆快照
在性能优化中,分析堆快照是必不可少的环节。
-Xmx20M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d://log)
3、错误处理
可以在系统发生 OOM 时,运行第三方脚本。如重置系统
4、获取 GC 信息
5、类和对象跟踪
6、控制 GC
7、使用大页
8、压缩指针
在 64 位虚拟机上,应用程序占的内存要远大于 32 位的,因为 64 位系统拥有更宽的寻址空间,指针对象进行了翻倍。
1、tomcat 优化
2.当发现产生了 GC 时,看下是否需要增加新生代大小
set CATALINA_OPTS=%CATALINA_OPTS% -Xmx32M -Xms32M
3.如果发现有人使用了显示的 GC 调用,可以禁止掉 set CATALINA_OPTS=%CATALINA_OPTS% -XX:+DesableExplicitGC
4.扩大新生代比例 set CATALINA_OPTS=%CATALINA_OPTS% -XX:NewRatio=2
5.给新生代使用并行回收 set CATALINA_OPTS=%CATALINA_OPTS% -XX:UseParallelGC
6.当确保 class 安全的时候,可以关闭 class 校验 set CATALINA_OPTS=%CATALINA_OPTS% -Xverify:none
2、JMeter 介绍和使用
JMeter 是一款性能测试和压力测试工具。
下载路径:https://jmeter.apache.org/download_jmeter.cgi

下载解压之后,进入 bin 目录,点击 jmeter.bat 启动。
右键添加线程组

右键添加请求

添加结果视图
这里有很多结果视图,都可以选来试试。

3、案例
确认堆大小(-Xmx,-Xms),合理分配新生代和老年代(-XX:NewRatio,-Xmn,-XX:SurvivorRatio),确定永久区大小(-XX:PermSize,-XX:MaxPermSize),选择垃圾收集器,除此之外,禁用显示的 GC,禁用类元素回收,禁用类验证对性能也有提升。
实战的调优:
1、top 命令
2、sar 命令
3、vmstat 命令
统计 CPU、内存情况
4、iostat 命令
统计 IO 信息
5、pidstat
可以监控线程的
grant codebase "file:D:/Java/jdk1.8.0_112/lib/tools.jar" { permission java.security.AllPermission;};2、执行开启
jstatd -J-Djava.security.policy=D:/jstatd.all.policy
3、新开一个 cmd 窗口,执行 jps localhost:1099 即可远程监听
8.hprof 工具,程序运行时加上-agentlib:hprof=cpu=times,interval=10 可以导出函数执行时间。还可以使用-agentlib:hprof=heap=dump,format=b,file=d:/core.hprof 导出文件
1、BTrace 插件,可在不修改代码情况下给代码加日志
/* BTrace Script Template */import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*;@BTracepublic class TracingScript { /* put your code here */private static long startTime=0;//方法开始时调用@OnMethod(clazz="com.mmc.concurrentcystudy.test.BTraceTest",method="writeFile") //监控任意类的writeFile方法public static void startMethod(){ startTime=timeMillis();}@OnMethod(clazz="com.mmc.concurrentcystudy.test.BTraceTest",method="writeFile",location=@Location(Kind.RETURN)) //方法返回时触发public static void endM(){ print(strcat(strcat(name(probeClass()),"."),probeMethod())); print("["); print(strcat("Time taken:",str(timeMillis()-startTime))); println("]"); }}实例 2:
/* BTrace Script Template */import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*;@BTracepublic class TracingScript { /* put your code here */@OnMethod(clazz="/.*Test/",location=@Location(value=Kind.LINE,line=27)) //,监控Test结尾的类,指定程序运行到第27行触发public static void onLine(@ProbeClassName String pcn,@ProbeMethodName String pmn,int line){ print(Strings.strcat(pcn,".")); print(Strings.strcat(pmn,":")); println(line); }}实例 3:每秒执行
@BTracepublic class TracingScript { /* put your code here */@OnTimer(1000) //每秒钟运行public static void getUpTime(){ println(Strings.strcat("l000 msec:",Strings.str(Sys.VM.vmUptime()))); //虚拟机启动时间 } @OnTimer(3000) public static void getStack(){ jstackAll(); //导出线程堆栈 }}实例 4:获取参数
@BTracepublic class TracingScript { /* put your code here */ @OnMethod(clazz="com.mmc.concurrentcystudy.test.BTraceTest",method="writeFile") public static void any(String filename){ print(filename); }}1、下载 mat
https://www.eclipse.org/mat/
2、深堆和浅堆
浅堆:一个对象结构所占用的内存大小。
深堆:一个对象被 GC 后,可以真实释放的内存大小
略