由一个NPE问题引发的内部类概览

在实际工作中遇到这么一个序列化的问题,需要根据一个用户表的老用户进行拓展,每一个老用户需要派生几个不同业务线的新用户。方法是在部署之后,从传入的参数中读取Json数据构建Map,Map的 Key 值为老的用户Id,Value 值为老用户对应的新的用户 Id 表。 为此,在拓展的任务代码里加入了如下内部类用于接收 Json: public class SomeJob{ public void deserialization(String paramStr){ … } class FlushPair{ long oldUserId; List<long> newUserIds; //getter and setter and default constructor … } } </long> Json 的格式如下所示: [ { “newUserIds”: [119,120,121], “oldUserId”:1 }, { “newUserIds”:[122,123,124], “oldUserId\”:2 }, { “newUserIds”:[125,126,127], “oldUserId”:13 }, … ] Json 的字符串命名为 paramStr,在下面代码中被反序列化: import … Continue reading “由一个NPE问题引发的内部类概览”

Netty 一些组件的一些原理

一个典型的服务端启动操作大概是: public void run() throws Exception{ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try{ ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new SimpleChatServerInitializer()) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); System.out.println(“SimpleChatServer 已启动”); ChannelFuture future = bootstrap.bind(port).sync(); future.channel().closeFuture().sync(); }finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); System.out.println(“SimpleChatServer 已关闭”); } } (以下内容请结合源码看, 善用 idea 的快捷键 ctrl + b / ctrl … Continue reading “Netty 一些组件的一些原理”

Netty 概念与名词

系列前言 Netty 作为使用最广泛的网络IO通信框架, 每一个合格的 Java 后台的开发者都应该对其了如指掌. 但是由于 Netty 项目涉及到比较多的版本迭代, API 也比较丰富. 源码在阅读上相对有一定难度, 所以本系列文章也无法确定更新计划与文章深度, 只能如同拾人牙慧, 外加自己一些浅显的见解, 拼凑出一个仅供自己复习的知识框架 本篇前言与其他的技术不同, 由于 Netty 的应用实在过于普遍又十分重要, 例如阿里广泛使用的 hsf 与 RocketMQ. 所以本系列文章会从如何使用开始, 接下来涉及到源码原理部分, 最后总结其特点与应用位置. 概念与名词 在上一篇文章中, 在 Java NIO 中引入了 Channel/Selector/Select 等概念, 在 Netty 中还需要了解以下概念 Reactor Reactor 并不是 Netty 特有的概念, 而是相对于 BIO 的 Acceptor 的概念提出的, Reactor 翻译叫反应堆, 其实更应该叫 Notifier/Dispatcher. 由于计算机中 CPU 的速度远大于 … Continue reading “Netty 概念与名词”

Java NIO 与 Selector

本篇总结一下 Java NIO相关的知识点与源码 Java NIO 属于比较基础的 Java 知识点, 但是出于一些不可名状的原因, Java NIO 成了长期没有关注的盲点. 由于与 netty 息息相关, 在不远的未来将会用到, 所以在这里特意总结一下. Channels 与 Buffers 在 Java 标准的输入输出控制时, 我们往往控制的是字节流或者字符流. 由于要满足 NIO (Non-block IO) 的需求, 所以我们需要使用 channels 和 buffers. channel 和流提供的功能相类似, 但是区别在于: i. channel 既可以用于读也可以用于写, 但是流一般只用于读或者写. ii. channel 可以异步的读写, 这是 NIO 最大的要求 iii. channel 总是往 Buffer 中读, 或者从 Buffer 中写. channel … Continue reading “Java NIO 与 Selector”

Java Lambda 表达式与函数式编程

  本篇总结一下 Java 8 的特性之一 lambda 表达式与函数式编程 从匿名类到匿名函数再到 lambda 表达式 在很久以前(2013年前后) 第一次接触 Java 线程时, 线程是这么写的: Runnable r = new MyTask(); Thread t = new Thread(r); t.start(); class MyTask implements Runnable(){ @Override public void run(){ //do something } } (当然也可以使用扩展 Thread 类的方法新建 Thread 启动 Thread.) 出于对接口概念的不清晰, 这样的代码需要初学者比较长的时间才能熟悉. 后来, 如果只是为了简单执行多线程任务, 匿名类取代了这种明确定义接口的方法: Thread t = new Thread(new Runnable(){ … Continue reading “Java Lambda 表达式与函数式编程”

java.util.concurrent的执行器与线程池

本篇主要继续盘点 java.util.concurrent 中的执行器与线程池 ThreadPoolExecutor的构造 大量的线程创建与销毁是一个十分消耗系统资源的操作, 通过 线程池-线程工厂-线程执行器 可以高效的使用线程资源, 线程可以被重复利用, 适合大量短线程的情景. ThreadPoolExecutor 是线程池中非常重要的一个类. 其继承关系如下图所示 使用 TheadPoolExecutor 我们可以得到一个线程执行器,方便地执行各种大量重复的线程. ThreadPoolExecutor 有多种构造方法: public class ThreadPoolExecutor extends AbstractExecutorService { ….. public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long … Continue reading “java.util.concurrent的执行器与线程池”

java.util.concurrent的工具

本篇主要继续盘点 java.util.concurrent 中的工具包 ReentrantLock/Semaphore/CountDownLatch/CyclicBarrier/Phaser/Exchanger 如上一篇文章中写到 ReentrantLock 提供了重入锁的调用, 通过 lock()/unlock() 实现加锁/解锁的操作. 例如 class LockTest implements Runnable { ReentrantLock lock; public LockTest(ReentrantLock lock) { this.lock = lock; } @Override public void run(){ try{ lock.lock(); //do something }finally{ lock.unlock(); } } } /* * * * * * ReentrantLock lock = new ReentrantLock(); Thread t1 = new Thread(new … Continue reading “java.util.concurrent的工具”

AbstractQueuedSynchronizer

本篇主要继续盘点java.util.concurrent中的工具包 AbstractQueuedSynchronizer 曾在先前的文章里介绍过, ReentrantLock是基于API实现的重入锁的数据结构. 在API层面的具体实现而是依靠AbstractQueuedSynchronizer实现的. AbstractQueuedSynchronizer本质是一个修改后 CLH(Craig, Landin and Hagersten) 队列. CLH队列是由FIFO的队列实现的, 简单的 CLH 队列节点存在一个 locked 域, 每一个节点存放一个竞争资源的线程. 当一个节点尝试获取锁时, 会在队列尾端插入一个节点, 对队列的 tail 域进行 CAS 操作, 反复试图使将节点插入到队列尾端. 并获取其前驱节点的 locked 的域, 该线程会在其前驱节点的 locked 域旋转, 直到前驱节点释放锁将 locked 置为 false. Java AbstractQueuedSynchronizer 是一个Abstract类, ReentrantLock 中的 Sync 类继承了该类, Sync 又被 NonfairSync 和 FairSync 所继承, 分别用于公平锁与非公平锁. ReentrantLock 默认是非公平锁, 即加锁时无需考虑排队问题, 可以直接尝试获取锁, 获取失败会假如排队队列. … Continue reading “AbstractQueuedSynchronizer”

1 Comment so far

内存模型与线程

本篇主要用于盘点Java中常见的多线程知识 1.复杂的内存模型 何为Java的内存模型(JMM)? JMM实际上是为了避免C/C++在不同机器上内存适配的问题, 尝试定义程序中各个变量的访问规则, 而不是说简单的将内存划分为堆/栈. Java内存模型规定了两种内存: 工作内存(例如对应于虚拟机栈局部变量)与主内存(对应于堆的对象实例). 线程对变量的所有操作都必须在工作内存中进行, 而不能读写主内存中的变量. (以下内容摘自深入理解JVM虚拟机) 关于主内存与工作内存之间的交互协议, 即一个变量如何从主内存拷贝到工作内存. 如何从工作内存同步到主内存中的实现细节. java内存模型定义了8种操作来完成, 这8种操作每一种都是原子操作. 8种操作如下: i. lock(锁定):作用于主内存, 它把一个变量标记为一条线程独占状态. ii .unlock(解锁):作用于主内存, 它将一个处于锁定状态的变量释放出来,释放后的变量才能够被其他线程锁定. iii. read(读取):作用于主内存, 它把变量值从主内存传送到线程的工作内存中,以便随后的load动作使用. iv. load(载入):作用于工作内存, 它把read操作的值放入工作内存中的变量副本中. v. use(使用):作用于工作内存, 它把工作内存中的值传递给执行引擎,每当虚拟机遇到一个需要使用这个变量的指令时候,将会执行这个动作. vi. assign(赋值):作用于工作内存, 它把从执行引擎获取的值赋值给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操作. vii. store(存储):作用于工作内存, 它把工作内存中的一个变量传送给主内存中,以备随后的write操作使用. vii. write(写入):作用于主内存, 它把store传送值放到主内存中的变量中. 并且必须满足如下规则: i. 不允许read和load、store和write操作之一单独出现, 以上两个操作必须按顺序执行, 但没有保证必须连续执行, 也就是说, read与load之间, store与write之间是可插入其他指令的. ii. 不允许一个线程丢弃它的最近的assign操作, 即变量在工作内存中改变了之后必须把该变化同步回主内存. iii. 不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中. iv. … Continue reading “内存模型与线程”

Collection 与 HashMap

  本篇主要总结集合框架/Hashmap相关的内容 介绍之前先记住这张图 虚线(点/短线)分别表示了 Interface/Abstract class, 实线表示了 Class, 箭头表示了实现或者继承. 1.Collection 最基本的集合接口, 实现了一些基础方法, 例如 size(), isEmpty(), add(), remove(), contains(), clear() 等等. Collection 有三个子接口: List, Set, Queue. List下有AbstractList接口, Vector, Stack, ArrayList, LinkedList都实现了该接口.(LinkedList还实现了Deque/Queue接口) Set下有SortedSet和AbstractSet虚类, HashSet实现了AbstractSet虚类, TreeSet二者都实现了. (HashSet 是用HashMap实现) 2. TreeSet/TreeMap TreeSet/TreeMap可以看作 HashSet和HashMap的排序版本, 例如TreeSet可以使用迭代器迭代输出排序之后的Set. (Set中的类型需要支持Comparable接口.) TreeMap则可以实现HashMap的排序. 其具体实现是红黑树. 简单介绍一下红黑树, 满足以下几个性质的二叉搜索树即为红黑树: i. 节点是红色或者是黑色 ii. 根节点是黑色 iii. 叶子(Nil)结点是黑色 iv. 红色节点的子节点都是黑色 v. 从任何一个结点向下出发的所有路径都应该包含数量相等的黑色节点 … Continue reading “Collection 与 HashMap”

1 Comment so far