3 构建Java中间件
3.1 什么事中间件?
中间件不是最上层的应用也不是最底层的支撑系统,中间件在项目中起到桥梁作用,特定中间件是解决特定的场景问题的组件。让开发聚焦于自己的业务。
常用中间件的分类:
- 远程过程调用和对象访问中间件:主要解决分布式环境下应用的互相访问问题,
- 消息中间件:解决应用之间的消息传递,解耦,异步的问题。
- 数据访问中间件:主要解决应用访问数据库的共性问题的组件。
3.2 Java中间件的基础知识
3.2.1 JVM
Java源码通过编译器变成Java字节码
JVM加载Java字节码
3.2.2 垃圾回收与内存堆布局
Java通过虚拟机进行垃圾回收。
一般新的对象被分配在young的Eden区,也有可能直接分配在Tenured。
在进行垃圾回收的时候,Eden区中存活的对象会被复制到空的Survivor区,而下次新生代垃圾回收的时候,Eden区存活的对象和这个Survivor区中存活的对象会被复制到另外那个Survivor区域,并且清空当前的Survivor区域。经过多次新生代垃圾回收,还存活的对象被移动到年老代,而年老代的空间也会根据一定的条件进行垃圾回收。
新生代:
串行GC -- Serial Copying
并行GC -- ParNew
并行回收GC -- Parallel Scavenge
年老代:
串行GC -- Serial GC
并行MS -- Parallel MSC
并行Compacting GC -- Parallel Compacting GC
并发GC -- CMS
3.2.3 Java并发编程
线程池
synchronized
任何两个线程之间调用互斥。 同步静态代码块。
同一对象之间的两个方法互斥。 同步代码块。
- ReentrantLock
tryLock:调用的时候,如果锁被其他线程占有返回false。
可以构造公平锁,公平锁的好处就是等待锁的线程不会饿死,但是整体效率低。
- volatile
可见性是指在一个线程中修改变量以后,在其他线程可以看得到这个数值。
volatile关键字保证了同一个变量在多线程中的可见性,所以它更是用于修饰作为开关状态的变量。
int key1;
public int getKey1(){
return key1;
}
对于调用getKey1获取当前线程中的副本,这个值不一定是最新的。
对于setKey1来说,操作的是当前线程中的副本,所以其他线程看不到最新的值。
volatile int key2;
public int getKey2(){
return key2;
}
对于调用getKey2来说,volatile修饰保证这个变量没有线程副本,只会放在主存,所以得到的值是最新的值。
对于setKey2来说,直接操作主存,其他线程肯定会看到新值。
int key3;
public synchronized int getKey2(){
return key3;
}
同步关键字保证线程主存与本地副本的同步,所以得到的值是最新的值。
- Atomics
提供了原子操作,计数器操作。
- wait,notify和nitifyAll
notify唤醒一个线程,noitfyAll唤醒所有线程。
对wait,notify和notifyAll调用都必须是在对象的synchronized快中。
- CountDownLatch
线程都到达了预期状态活完成预期工作时触发事件。
统计数据:分布计算 latch.countDown(),然后合并数据latch.await();
- CyclicBarrier
循环屏障,协同多个线程,让多个线程在这个屏障前等待,直到所有线程都到达了这个屏障的时候,在一起执行后面的计算。
可以循环使用。
- Semaphore
信号量:
- Exchanger
用于两个线程交互数据
线程会阻塞在exchange方法上,直到另一个线程也到了同一个Exchanger的exchange方法。
- Future和FutureTask
// 远程调用回阻塞
1:HashMap<String,Object> map = rpc.getDataFromRemote();
doOther();
// 远程调用提交给线程池执行
2: Future<HahsMap<String,Object>> fuctur = rpc.getDataRemote();
doOther();
// 获取数据的时候阻塞
future.get();
并发容器
动态代理
控制在执行方法之前,方法之后能进行处理相关操作。
- 反射
常用操作库
Javassist
cglib
asm
bcel
- 网络通信实现
框架Mina,Netty
3.3 分布式系统与Java中间件
WebApp和Service中间引入服务框架,解决了集群之间的通信问题。
在应用和数据库之间,引入分布式数据层可以方便我们操作已被分库分表的数据库节点。