java 基础 ----基本数据结构

基本数据类型

  • 字符型(char)

java 采用 unicode 编码, 使用 2 个字节表示一个字符,所以java中的一个字符是 2 个字节
c 语言使用的是 ASCII 编码,一个 char 占用 1 个字节。

由于是无符号的,且 2 个字节 32 位长度,那么其访问是 0 到 65535 。

  • 布尔类型: boolean

  • 数值类型: 有符号数值类型,最高位表示符号位
    byte : 1 字节
    short : 2 字节
    int : 4 字节
    long : 8 字节
    float : 4 字节
    double : 8 字节

更多

编辑器之 tmux

install

mac 上安装

1
brew install tmux

需要使用的时候只需要在命令行输入 tmux
tmux 所有的操作都带了一个 prefix , 这也是 tmux 用起来比较麻烦的地方. 默认的 prefix 是 ctrl + b

session

直接在终端查看 session 相关信息

1
2
3
4
tmux ls 列出会话
tmux attach -t session 进入某个会话
tmux -r 连接上个断开的session
tmux new -s session -d 在后台建立会话

进入 tmux 后查看 session 相关信息

1
2
3
ctrl+b s 查看/切换session
ctrl+b d 离开(detach)session
ctrl+b $ 重命名当前session

更多

JAVA ClassLoader

java 类加载器概述

要使用一个类必须要先将这个类加载到内存中, JVM 将编译后的字节码文件, 即 .class 文件加载到内存中, 并生成一个 java.lang.Class 对象.

字节码文件通常有一下来源:

  • 本地磁盘文件系统 class 文件
  • JAR 包中加载 class 文件
  • 网络地址加载 class 文件
  • 动态编译一个 java 源文件, 并执行加载

类加载器

java 中的类加载器是通过双亲委派模型来实现的, 有如下特点

  • 类的加载过程采用委托模式实现. 某个特定的类加载器在接到加载类的请求时, 首先将加载任务委托给父类加载器, 依次递归, 如果父类加载器可以完成类加载任务, 就成功返回; 只有父类加载器无法完成此加载任务时, 才自己去加载.

  • JVM 预定义了三种类加载器

    • 根类加载器(Bootstrap ClassLoader). 由C++实现, 负责将<Java_Runtime_Home>/lib下面的类库加载到内存中, 如 rt.jar
    • 扩展类加载器(Extension ClassLoader). 负责将 <Java_Runtime_Home >/lib/ext 或者由系统变量 java.ext.dir指定位置中的类库加载到内存中. 开发者可以直接使用标准扩展类加载器.
    • 系统类加载器(System ClassLoader). 负责将系统类路径(CLASSPATH)中指定的类库加载到内存中. 开发者可以直接使用系统类加载器。

Nginx 复习

WHY

对自己学习 nginx 的一个总结, 能熟练使用和配置 nginx , 熟悉相关知识和原理.

安装

  • 基本安装和配置文件位置

我这里使用的是 openresty, 我使用的是 ubuntu 安装非常简单, 具体请参考 openresty官网

执行 ./configure 之后可以看到

1
2
3
4
5
6
7
8
9
10
11
12
13
nginx path prefix: "/usr/local/openresty/nginx"
nginx binary file: "/usr/local/openresty/nginx/sbin/nginx"
nginx modules path: "/usr/local/openresty/nginx/modules"
nginx configuration prefix: "/usr/local/openresty/nginx/conf"
nginx configuration file: "/usr/local/openresty/nginx/conf/nginx.conf"
nginx pid file: "/usr/local/openresty/nginx/logs/nginx.pid"
nginx error log file: "/usr/local/openresty/nginx/logs/error.log"
nginx http access log file: "/usr/local/openresty/nginx/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp"

执行 make && make install 安装, 安装完成最后一行有如下提示, 我们可以直接执行 openresty 命令.

1
ln -sf /usr/local/openresty/nginx/sbin/nginx /usr/local/openresty/bin/openresty
  • 设置环境变量

为了后面启动 OpenResty 的命令简单一些, 不用在 OpenResty 的安装目录下进行启动, 修改环境变量添加一下内容

1
2
3
sudo vim /etc/profile
export PATH=/usr/local/openresty/nginx/sbin:$PATH
source /etc/profile
  • 非 root 用户启动

我这里使用自己创建的 admin 账户启动 nginx 报错

1
2
3
admin@iZ2zecl4i8oy1qsj9vq9ivZ:/usr/local/openresty/bin$ ./openresty
nginx: [alert] could not open error log file: open() "/usr/local/openresty/nginx/logs/error.log" failed (13: Permission denied)
2016/11/10 15:08:48 [emerg] 9765#0: mkdir() "/usr/local/openresty/nginx/client_body_temp" failed (13: Permission denied)

为了方便普通用户执行一些特权命令, SUID/SGID程序允许普通用户以root身份暂时执行该程序,并在执行结束后再恢复身份 需要设置下

1
sudo chmod u+s nginx

nginx 命令

启动

1
nginx

平滑启动

1
2
nginx s- reload
kill -HUP `cat /usr/local/openresty/nginx/logs/nginx.pid`

检查 nginx.conf 配置文件是否正确

1
2
nginx -t
nginx -t /usr/local/openresty/nginx/conf

停止 nginx

1
nginx -s stop

正向代理和反向代理

一般来说大家通常说的代理指的是正向代理(forward proxy), 正向代理和反向代理(reverse proxy)的区别如下图:

正向代理和反向代理的区别

参考 正向代理和反向代理

一句话总结:

1
2
正向代理: 代理端 代理的是 客户端
反向代理: 代理端 代理的是 服务端
  • nginx 做为反向代理服务器配置
  • nginx 作为 lb 的配置

nginx 做负载均衡, 后端其中一个 upstream 挂掉 nginx 并不知道, 需要配置, 参考如下链接

http://serverfault.com/questions/480241/nginx-failover-without-load-balancing
http://serverfault.com/questions/140990/nginx-automatic-failover-load-balancing

需要设置:

1
2
proxy_next_upstream
proxy_connect_timeout

具体设置方式参考nginx官方文档
http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream

  • 打发打发

JVM 学习笔记

JVM 的基本结构

下图是 JVM 执行流程的基本介绍

ClassLoader 负责将编译后的 Class文件加载到内存当中, JVM 的内存模型将内存空间分为

  • 方法区
  • JAVA堆
  • JAVA栈
  • 本地方法区

虚拟机运行时, 需要记录下一条指令的地址, 就是 PC寄存器
执行引擎负责执行类的代码

PC 寄存器

  • 每个线程拥有一个 PC 寄存器
  • 在线程创建的时候创建
  • 总是指向下一条指令的地址
  • 执行本地方法的时候值为 undefined

方法区

保存和装载类的元数据信息, 对类进行描述

  • 类型的常量池
  • 字段, 方法信息
  • 方法字节码

方法区通常同永久区(Perm)关联在一起, 用于保存相对稳定和静止的数据

JAVA 堆

堆具有以下特点:

  • 应用系统分配的对象保存在堆区
  • 所有线程共享堆. 也就是说在堆上分配了一个对象, 所有的线程都可以访问
  • 对分代的 GC 来说, 堆也是分代的

JAVA 栈

栈具有以下特点:

  • 线程私有
  • 栈由一系列帧组成(栈帧),
  • 栈帧由三部分组成:栈帧保存一个方法的局部变量, 操作数栈, 常量池指针
  • 每一个方法调用都会创建一个帧, 并压栈

JVM 的运行机制

为什么String类被设计为不可变

翻译 为什么 String 被设计成不可变的

在 JAVA 中 String 被设计为不可变, 也就是说 String 类的实例不能被修改。实例被创建的时候, 实例中所有的信息也被一并初始化好了, 所有的这些信息都不能再被修改. 不可变类有许多优点. 一个好的答案体现在对内存, 并发, 数据结构等的理解.

  • 字符串池的要求

字符串常量池存储于 JVM 的方法区. 当创建一个字符串的时候, 如果一个字符串已经在常量池中存在, 会返回字符串的引用而不是在重新创建一个字符串

  • 缓存 hashcode

String 的 hashcode 方法在 JAVA 中被频繁的被使用, 比如 HashMap. 不可变可以保证 hashcode 总是一样的, 这样能够被缓存而不必担心改变. 也就是说, 没有必须在每次使用的时候都去计算一次 hashcode. 这样效率更高.

String 类中, 有这样的代码

1
2
/** Cache the hash code for the string */
private int hash; // Default to 0
  • 促进使用其它相关的对象

参考下面的例子

1
2
3
4
5
6
7
8
HashSet<String> set = new HashSet<String>();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));
for(String a : set){
a.value = "a";
}

上面的例子中, 如果 a 是可变的, 那么就违背了集合的设计(set 表示集合中包含不重复的元素), 上面的例子是为了简单起见而设计的, 事实上 String 类中并不存在 value 这个字段.

  • 安全

String 被广泛地用着其它类的参数, 比如: 网络连接, 文件创建等等. 如果 String 是可变的, 一个连接或是文件就能够被改变, 这样会导致很严重的安全问题. 方法认为它连接上了一台机器, 但是事实上不是. 字符串作为参数的时候, 可变的字符串在反射的时候也可能引起安全问题.

  • 不可变对象天然是线程安全的

因为不可变对象不能被改变, 他们能够在多线程之间被共享, 这就消除了执行同步的要求.

简而言之, 因为安全和效率的原因 String 类被设计为不可变.

参考: http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/

RESTful简单介绍

RESTful介绍

本文主要包含以下内容:

  • 为什么要用RESTful
  • RESTful的定义
  • RESTful的五个关键内容
    • 资源与URI(Resource URI)
    • 统一资源接口(Uniform Interface)
    • 资源的表述 (Representation)
    • 状态的转移 (State Transfer)
    • 超文本驱动 (Hypertext Driven)
  • 简单比较下REST和RPC两种API调用风格

需要注意的是本文只对RESTful进行简单的介绍, 很多内容可探讨的就比较多, 比如安全及授权, 超文本驱动, 所以只对这些内容做简单介绍. 另外文章中的很多内容在实际开发中会有所取舍, 因此本文不是实际开发中的规范, 但是对理解规范是有很大作用的. 另外, 权衡各方面利弊后, 我们会在短期内给出相应的开发规范.

文中出现的错误或表述不清楚的地方, 欢迎大家指正.

更多