JasonWang's Blog

JasonWang's Blog

Java Annotation

在Java中,Annotation(注解)是一种可添加到源码中的句法元数据(Java annotation),类、方法、变量、参数以及包都可以进行注解。

注解主要有如下几个用途:

  • 为编译器提供信息: 编译器使用annotation来检测错误或者消除警告;
  • 编译或者部署时处理: 可以利用注解信息产生代码,XML文件等;
  • 运行时处理: 可在运行时检查注解,产生相应的代码;
如何在Android中查看进程状态

在Android开发调试过程中,常需要使用ps指令用于获取当前系统进程的快照信息(如果想要获取进程动态信息,则需要使用top命令)。通过ADB SHELL连接上手机后,输入adb shell命令进入shell控制台, 输入ps即可查看当前系统所有进程信息:

ps all process

HTTP简介

HTTP(Hypertext Transfer Protocol)即超文本传输协议,是一种用于传输文本、音视频等超媒体(hypermedia)的应用层协议。HTTP从1990年开始就应用于WWW(World Wide Web)服务中,其发展变化与WEB服务紧密相连。这篇文章,就来看看HTTP协议的基本概念。

基本概念

HTTP协议允许不同类型的客户端与服务端进行通讯,支持不同的网络配置,并不依赖于特定的系统。在消息交换过程中,不保存任何状态(state-less,状态无关)。HTTP协议请求基于Request/Response,一个客户端向服务端发送request,该请求包含了Request Method, URL,协议版本以及请求的资源类型;服务端得到请求后,返回一个response,包括状态信息(协议版本,状态码)以及请求的资源。这样一次Request/Response的过程我们称为一次HTTP会话(session),大致有三个阶段:

  1. 客户端与服务端建立一个TCP链接;
  2. 客户端发送数据请求,等待回应;
  3. 服务端处理请求,返回结果并提供一个状态码与资源;
常用哈希函数C实现

哈希函数(hash function)是一个将某个集合内的元素映射到一个大小固定的元素集合的函数,其在数据查找、数据去重等方面有着许多的应用。这里,就来看看常用的一些哈希函数是如何来实现的。

0. RsHash

最简单的一种Hash函数实现方法,来自于Rober Sedgwicks的C语言算法书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

unsigned int RsHash(const char* str, unsigned int len){
unsigned int b = 378551;
unsigned int a = 63689;
unsigned int hash = 0;

for(int i = 0; i < len; ++i){
hash = hash * a + (*str++);
a *= b;
}

return hash;
}


cache揭秘

缓存(Memory Cache)在一般意义上是指一种用于存储当前或者历史数据的硬件或者软件结构,其目的是加速数据的存取,提升系统效率。目前大多数的计算机系统都会在软件或者硬件层面集成有各种cache, 比如:

  • L2(Level 2 cache,3-10个CPU周期)作为L1(Level 1 cache, 1-3个CPU周期)的缓存, 同样L3又作为L2的缓存, 从而形成一个多级缓存的结构
  • TLB(Translation Lookaside Buffer)用于系统页表查找的缓存, 可以加速虚拟内存与物理内存的地址转换
  • Main Memory(主存)是磁盘数据的缓存, 保存了部分使用的磁盘数据, 改善系统运行的性能

一般来说, 现代的多核CPU系统都有多级的缓存结构, 简图如下:

multiple level cache

这篇文章将要讨论的cache是指CPU与主内存之间的一种基于SRAM(Static Random Access Memory)存储结构。

自计算机诞生以来,CPU的性能大致都按照摩尔定律以每年50%的速度递增,而主内存RAM(Random Access Memory)的性能增速却只有7%,因此在CPU性能与主内存性能之间渐渐形成了一个鸿沟:

Android进程Crash处理流程

之前的一篇文章,讲到了应用程序无响应(ANR)时Android的处理逻辑。这篇文章,就来分析下应用进程发生崩溃(Crash)时,Android是如何处理的?总的说来,Android主要有两大类Crash:

  • Java(JVM)层: 应用程序发生运行时错误(如空指针,浮点运算错误,数据索引超出界限)或者系统进程崩溃(长时间无响应);
  • Native层: native进程或者kernel发生运行时错误;
Android中的任务管理

Activity是Android负责与用户交互的实体。一个应用一般由多个Activity组成;一个Activity不仅可以打开应用内的Activity,也可以打开其他应用内的Activity,比如通过一个名为android.intent.action.VIEW的Intent事件可以打开浏览器;通过android.intent.action.DIAL可以向CALL发送拨号请求。一系列的Activity组合在一起(完成某个特定的“任务“)构成了一个任务(一个后进先出的队列,被称为back stack),而多个任务又构成了一个任务栈(后台可以有多个任务栈,但系统如需恢复内存,则会杀死部分应用,清空部分任务,以释放内存,因此长时间后应用状态会丢失)。以下图为例,图中的back stack一开始只有一个Activity1;接着在Activity1中启动Activity2,此时Activity2位于队列的顶部,而Activity1位于栈底(Activity1处于Stop状态),而Activity2又启动一个Activity3,同样,Activity3压入栈顶。如果此时通过回退键(Back)用户离开Activity3,则Activity3从栈中清除,被系统销毁,而Activity2则恢复到可见状态(resume)。

Android ANR处理流程

ANR即Application Not Responding, 应用无响应:当应用在某一个时间内无法及时响应用户请求时,系统会弹出一个对话框,告知用户应用无法响应。此时,用户可以选择关闭应用。对于Android应用来说,有一个UI线程(主线程)专门负责与用户交互,如果在此线程中进行耗时的操作,比如读取磁盘数据、从网络下载资源等IO操作,通常会导致UI线程阻塞,从而无法及时处理用户的输入请求,发生ANR。

Android是通过AMS跟WMS来监控应用响应状态的,一般有如下两种ANR情况:

  • 应用在给定时间内没有对用户输入(按键或者触屏操作)做出响应,通常是5s;
  • 广播接收者(BroadcastReceiver)没有在10s内处理完成;

对于输入无响应的情况,native监控到输入无响应时,则告知WMS,最后由WMS发送消息告诉AMS,某个应用发送了ANR,最后AMS会弹出Application Not Responding的对话框,请求用户关闭应用;对于广播无响应的情况是由AMS负责处理的,AMS对于每个发送出去给广播接收者的广播都有一个10s的定时,如果广播接收者在10s内尚未处理完,则视为无响应,因此也会弹出Application Not Responding

Java并发编程之锁

Java语言synchronized关键字自带了一个内置的隐性锁(implicit lock),使用起来方便简单,但是内置锁一旦使用,则会强制将某个代码块加锁或者解锁,而且内置锁并不支持可中断的获取锁。从Java5.0开始,提供了一个并发工具包java.util.concurrent.*,实现了显性锁(explicit lock)ReentrantLock(可重入锁,可多次获取同一个锁);ReentrantLock实现了与synchronized一样的功能,确保并发过程中数据的互斥访问与可见性。获取ReentrantLock相当于进入一个synchronized代码块,而释放ReentrantLock则相当于从一个synchronized代码块退出。ReentrantLock实现了如下Lock.java接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

public interface Lock {
//获取锁
void lock();

//获取锁,可响应中断
void lockInterruptibly() throws InterruptedException;

//尝试获取锁,如果可用则返回TRUE,否则返回FALSE
boolean tryLock();

//尝试在给定时间内获取锁,如果超时或者发生中断,则返回FALSE
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

//释放锁
void unlock();

//创建与该锁绑定的Conidition变量
Condition newCondition();
}


Java并发编程之原子操作

在古希腊时代,哲学家Democritus(德谟克利特)提出了关于物质构成的理论:所有物质都由不可分割的元素组成,这种元素被称之为原子(atom)。编程中所说的原子性(atomic)借用了这个概念, 用于表示某个代码指令动作的不可中断性。在之前的一篇文章(Java Memory Model)时,提到多线程并发访问共享数据时,会出现数据竞争,从而导致数据不一致的情况。比如对一个整型变量进行加一的操作: ++counter,表面上看,这是一个单一原子操作,但实际上这个操作有三个步骤:首先,需要从内存中(有可能是cache中)加载到寄存器;接着,将该值加一;最后需要将寄存器中的值写入内存。这样,在多个线程访问的情况,上述几个步骤出现交织执行,就可能出现各个线程读写数据不一致的情形。

Atomic Theory: http://www.softschools.com/timelines/atomic_theory_timeline/95/

于是,有了原子操作。原子操作确保了执行的不可中断,因而能避免数据冲突。Java从5.0开始有一个atomic的工具包专门支持intlong以及引用变量的原子操作,而在硬件层面,目前大部分处理器都支持诸如CAS(CompareAndSet/CompareAndSwap),FAA(FetchAndAdd)等原子指令。在介绍Java中的原子操作类之前,先来了解下硬件层面的原子指令。

avatar
JasonWang
生命短暂,莫空手而归