java核心系列(十二)-java对象大小

对象大小

1,64位系统

new java.lang.Object() 占用了 16 bytes
new byte[0] 占用了 24 bytes

1
2
3
4
5
6
class A {
byte x;
}
class B extends A {
byte y;
}

new A() 占用了 24 bytes
new B() 占用了 32 bytes= 24+pad A(8)

1
2
3
class C {
Object obj = new Object();
}

new C() takes 40 bytes= obj+obj ref +C = 16+8+16

2,参考资料

分布式一致性协议

一,概述

为了解决分布式一致性问题,出现了大量的一致性协议和算法,本文主要介绍2pc,3pc,paxos和zab算法。

二,二阶段提交(2pc)

参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

2.1 基本算法

  • a,第一阶段(请求阶段)
    在请求阶段,协调者通知事务参与者准备提交或者取消事务,然后进入表决过程。在表决过程中,参与者将报告协调者自己的决策:同意或者取消。

  • b,第二阶段(提交阶段)
    在提交阶段,协调者将基于第一个阶段的投票进行决策:提交或取消。当所有的参与者同意提交事务时,协调者才通知所有的参与者提交事务,否者通知所有的参与者取消事务。

2.2缺点

  • 同步阻塞,所有参与该事务的逻辑都将进入阻塞状态
  • 单点问题,协调者故障
  • 数据不一致,网络原因只有部分参与者收到commit请求

三,三阶段提交(3pc)

2pc的改进版本,将请求阶段一分为二,形成能否提交,预提交,提交三个阶段。

3.1基本算法

  • a,第一阶段(能否提交阶段)
    协调者询问参与者事务能否执行,参与者在正常情况下返回Yes状态,否者返回No。

  • b,第二阶段(预提交阶段)
    协调者根据反馈情况选择执行的预提交操作。

  • c,第三阶段(提交阶段)
    协调者发送提交请求,通知所有的参与者进行提交或者回滚。

3.2 改进

3pc相对与2pc最大的优点就是减少了参与者的阻塞范围。

四,Paxos协议

paxos用于解决多个节点间的一致性问题。2pc与3pc用于保证属于多个数据分片上的操作的原子性。

4.1 基本算法

4.1.1情况一

在大多数情况下,proposer只有一个,它的步骤如下:

  1. 批准(accpet):Proposer发送accept消息要求所有其他节点接受某个提议值,acceptor可以接受或者拒绝。
  2. 确认(acknowledge):如果超过一半的acceptor接受,意味着提议值已经生效,proposer发送acknowledge消息通知所有的acceptor提议生效。

4.2.1情况二

如果系统中出现了多个proposer的时候,他们各自发送不同的提议。如果proposer第一次发起的accept请求没有被acceptor中的多数派批准,那么,需要进行一轮完整的paxos协议:

  1. 准备(prepare): proposer首先选择一个提议号n给其他的acceptor节点发送prepare消息。acceptor接受消息后,如果提议号大于它已经回复的所有prepare消息,则acceptor将自己的上次接受的提议回复给proposer,并且不再回复小与n的提议。
  2. 批准(accept):Proposer收到了acceptor中的多数派对prepare的回复后,就进入批准阶段。如果之前的prepare阶段acceptor回复了上次接受的提议,那么,proposer选择其中一个最大的提议值发给acceptor批准:否者,proposer生成一个新的提议值发给acceptor批准。acceptor在不违背它之前prepare阶段的承诺下,接受这个请求。
  3. 确认(acknowledge): 如果超过一半的acceptor接受,提议值生效。proposer发送acknowledge消息通知给所有的acceptor。

4.2缺点

当有多个 proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功。

五,ZAP协议

构建高可用的分布式主备系统。

5.1 基本算法

  1. 选举Leader
    a,Leader要具有最高的zxid
    b,集群中大多数的机器得到响应并follow选出的Leader
  2. 同步数据
    a,发送数据同步指令
    b,follow事务回退
  3. 广播

六,参考资料

  1. 《从Paxos到Zookeeper-分布式一致性原理与实践》-倪超
  2. 《大规模分布式存储系统-原理解析与架构实践》-杨传辉
  3. Paxos算法

java核心系列(十一)-java内存模型

JMM内存概览

参考资料

linux搜索命令

一,grep

Syntax: grep [options] pattern [files]

搜索在文件中包含pattern的所有的行    
#grep John /etc/passwd
搜索在文件中不包含pattern的所有的行    
#grep -v John /etc/passwd
搜索在文件中包含pattern的行数
#grep -c John /etc/passwd
忽略大小写
#grep -i John /etc/passwd
搜索子目录,展现文件名和行
#grep -ri john /home/users
搜索子目录,只展现文件名
#grep -ril john /home/users

二,grep与正则的配合

行的开始^
grpe "^aa" message.logs
行的结尾$
grpe "aa$" message.logs
计算空行数
grep -c "^$" message.logs

三,find

Syntax: find [pathnames] [conditions]

查找文件名包含特定的字符
# find /etc -name "*mail*"
查找文件大小大于100M
#find / -type f -size +100M
查找文件在最近的60天未被修改
# find . -mtime +60
查找文件在最近的2天内被修改的
# find . –mtime -2
查看以.tar.gz并且大于100M的文件,并且删除
# find / -type f -name *.tar.gz -size +100M -exec ls -l {}
\;
# find / -type f -name *.tar.gz -size +100M -exec rm -f {}
\;

四,sed

Syntax: #sed ‘ADDRESSs/REGEXP/REPLACEMENT/FLAGS’ filename
Syntax: #sed ‘PATTERNs/REGEXP/REPLACEMENT/FLAGS’ filename

  • s is substitute command
  • / is a delimiter
  • REGEXP is regular expression to match
  • REPLACEMENT is a value to replace

FLAGS选项:

  • g 用REPLACEMENT代替所有的 REGEXP
  • n 可以是任意数字,用REPLACEMENT代替REGEXP的第n个实例。
  • p 打印匹配后的行
  • i 忽略大小写
  • w 将匹配后的行写入到文件中

我们也可以用( one of @ % ; : )的其中一个代替/

使用Linux-Unix替代Linux,只替代第一次
$ sed 's/Linux/Linux-Unix/' thegeekstuff.txt
使用Linux-Unix替代Linux,替代所有的
$ sed 's/Linux/Linux-Unix/g' thegeekstuff.txt
使用Linux-Unix替代Linux,替代第2次
$ sed 's/Linux/Linux-Unix/2' thegeekstuff.txt
将替换后的行输出并打印 ,-n 表示取消默认输出
$ sed -n 's/Linux/Linux-Unix/gpw output' thegeekstuff.txt
删除所有的以#开头的行  -e 表示在文本中编辑
$ sed -e 's/#.*//' thegeekstuff.txt

五,cut

Cut命令用于展现文本中的特定列。

Syntax: cut [-bn] [file] 或 cut [-c] [file] 或 cut [-df] [file]

  • -b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
  • -c :以字符为单位进行分割。
  • -d :自定义分隔符,默认为制表符。
  • -f :与-d一起使用,指定显示哪个区域。
  • -n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的范围之内,该字符将被写出;否则,该字符将被排除。

    从冒号(:)分隔文件中展现第一个字段.
    $ cut -d: -f 1 names.txt
    从冒号(:)分隔文件中展现第一到三个字段.
    $ cut -d: -f 1,3 names.txt
    展现每行的前8个字符
    $ cut -c 1-8 names.txt
    展现可用内存
    free | tr -s ‘ ‘ | sed ‘/^Mem/!d’ | cut -d” “ -f2

六,awk

Syntax:awk ‘/search pattern1/ {Actions}
/search pattern2/ {Actions}’ file

  • search pattern is a regular expression.
  • Actions – statement(s) to be performed.
  • several patterns and actions are possible in Awk.
  • file – Input file.
  • Single quotes around program is to avoid shell not to interpret any of its special characters

linux常用技巧

一,TOP命令

对于多核CPU,显示的是多个CPU的所占的百分比的总和,如需要查看每个核的情况,进入top视图后按1,就会按核来显示消耗情况。
默认情况下,TOP视图中显示的是进程的CPU消耗情况,在TOP视图中,按shift+h后,可按线程查看CPU的消耗情况。

二,进程启动

  1. & 在后台启动进程,如果关闭会话,进程也会终止
  2. nohup 在后台启动进程,如果关闭会话,进程不会终止
  3. at 定时启动命令 $ at -f backup.sh 10 am tomorrow
  4. watch 间隔启动 $ watch df -h

三,

java核心系列(十)-java新特性

一,概述

二,泛型

2.1 协变

数组是协变的,因为 Integer 是 Number 的子类型,数组类型 Integer[] 是 Number[] 的子类型,因此在任何需要 Number[] 值的地方都可以提供一个 Integer[] 值。另一方面,泛型不是协变的, List 不是 List 的子类型,试图在要求 List 的位置提供 List 是一个类型错误。这不算很严重的问题 — 也不是所有人都认为的错误 — 但泛型和数组的不同行为的确引起了许多混乱。

2.2 类型推断

当解析一个泛型方法的调用时,编译器将设法推断类型参数它能达到的最具体类型。 例如,对于下面这个泛型方法:

1
public static<T> T identity(T arg) { return arg };

和它的调用:

1
2
Integer i = 3;
System.out.println(identity(i));

编译器能够推断 T 是 Integer、Number、 Serializable 或 Object,但它选择 Integer 作为满足约束的最具体类型。

三,注解

注解早在J2SE1.5就被引入到Java中,主要提供一种机制,这种机制允许程序员在编写代码的同时可以直接编写元数据。
注解基本上可以在Java程序的每一个元素上使用:类,域,方法,包,变量,等等。

3.1 @Retention

这个注解注在其他注解上,并用来说明如何存储已被标记的注解。这是一种元注解,用来标记注解并提供注解的信息。可能的值是:

  • SOURCE:表明这个注解会被编译器忽略,并只会保留在源代码中。
  • CLASS:表明这个注解会通过编译驻留在CLASS文件,但会被JVM在运行时忽略,正因为如此,其在运行时不可见。
  • RUNTIME:表示这个注解会被JVM获取,并在运行时通过反射获取。

3.2 @Target

这个注解用于限制某个元素可以被注解的类型。例如:

  • ANNOTATION_TYPE 表示该注解可以应用到其他注解上
  • CONSTRUCTOR 表示可以使用到构造器上
  • FIELD 表示可以使用到域或属性上
  • LOCAL_VARIABLE表示可以使用到局部变量上。
  • METHOD可以使用到方法级别的注解上。
  • PACKAGE可以使用到包声明上。
  • PARAMETER可以使用到方法的参数上
  • TYPE可以使用到一个类的任何元素上。

3.3 @Documented

被注解的元素将会作为Javadoc产生的文档中的内容。注解都默认不会成为成为文档中的内容。这个注解可以对其它注解使用。

3.4 @Inherited

在默认情况下,注解不会被子类继承。被此注解标记的注解会被所有子类继承。这个注解可以对类使用。

3.5 @Repeatable

说明该注解标识的注解可以多次使用到同一个元素的声明上。

3.6 @FunctionalInterface

这个注解表示一个函数式接口元素。函数式接口是一种只有一个抽象方法(非默认)的接口。编译器会检查被注解元素,如果不符,就会产生错误。

四,lambada表达式

五,参考资料

  1. Java 理论与实践: 使用通配符简化泛型使用
  2. Java 理论和实践: 了解泛型
  3. java泛型
  4. Java 注解指导手册 – 终极向导
  5. Java深度历险(六)——Java注解
  6. 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

java核心系列(八)—java队列

队列概览

1,BlockingQueue

  • ArrayBlockingQueue,数组结构组成,其构造函数必须带一个int参数来指明其大小
  • LinkedBlockingQueue,由链表结构组成,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定
  • PriorityBlockingQueue,其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列。DelayQueue是一个支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素只有在延迟期满时才能从队列中提取元素。我们可以将DelayQueue运用在以下应用场景:

    缓存系统的设计:
    可以用DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存有效期到了。
    定时任务调度:
    使用DelayQueue保存当天将会执行的任务和执行时间,一旦从DelayQueue中获取到任务就开始执行,从比如TimerQueue就是使用DelayQueue实现的。

  • SynchronousQueue:一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。

  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。

2,Queue

  • PriorityQueue是个基于优先级堆的极大优先级队列。
    此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序(参阅 Comparable), 也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许 null 元素。

  • ConcurrentLinkedQueue一个无锁的并发线程安全的队列。对比锁机制的实现,使用无锁机制的难点在于要充分考虑线程间的协调。简单的说就是多个线程对内部数据结构进行访问时,如果其中一个线程执行的中途因为一些原因出现故障,其他的线程能够检测并帮助完成剩下的操作。这就需要把对数据结构的操作过程精细的划分成多个状态或阶段,考虑每个阶段或状态多线程访问会出现的情况。
    需要说一下的是,ConcurrentLinkedQueue的size()是要遍历一遍集合的,所以尽量要避免用size而改用isEmpty(),以免性能过慢。

3,Deque

LinkedList,ArrayDeque,非线程安全的,可以通过Collections的工具方法改造成线程安全的。
LinkedBlockingDeque

按照我们一般的理解,Deque是一个双向队列,这将意味着它不过是对Queue接口的增强。如果仔细分析Deque接口代码的话,我们会发现它里面主要包含有4个部分的功能定义。

  1. 双向队列特定方法定义。
  2. Queue方法定义。
  3. Stack方法定义。
  4. Collection方法定义。
1
2
3
4
5
6
7
8
\\Stack定义
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
public E peek();

4,参考资料

聊聊并发(七)——Java中的阻塞队列
Java多线程(五)之BlockingQueue深入分析
Java多线程(六)之Deque与LinkedBlockingDeque深入分析

java核心系列(七)—java线程

thread

1,锁

偏向锁(Biased Locking)是Java6引入的一项多线程优化。它通过消除资源无竞争情况下的同步原语,进一步提高了程序的运行性能。

轻量级锁(Lightweight Locking)本意是为了减少多线程进入互斥的几率,并不是要替代互斥。

轻量级锁也是一种多线程优化,它与偏向锁的区别在于,轻量级锁是通过CAS来避免进入开销较大的互斥操作,而偏向锁是在无竞争场景下完全消除同步,连CAS也不执行(CAS本身仍旧是一种操作系统同步原语,始终要在JVM与OS之间来回,有一定的开销)。

2,同步

wait:方法使当前线程暂停执行并释放对象锁标示,让其他线程可以进入synchronized数据块,当前线程被放入对象等待池中。

notify:将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,只有锁标志等待池中线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。

notifyAll:从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池中。

注意 这三个方法都是java.lang.Object的方法,调用时需要获取锁

3,实例方法

join:主要是让调用改方法的thread完成run方法里面的东西后, 在执行join()方法后面的代码。

t1.start();  
t1.join(); // wait t1 to be finished  
t2.start();  
t2.join(); // in this program, this may be removed

interupt:中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。

4,静态方法

sleep:在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。 通过调用sleep使任务进入休眠状态,在这种情况下,任务在指定的时间内不会运行。调用sleep的时候锁并没有被释放。

yield:线程调用yield()方法后,表明自己做的事已经完成,让出自己的cpu时间给其他线程使用。让出后,该线程可以重新获得cpu分配的权利,状态变为了可执行状态。(yield并不意味着退出和暂停,只是,告诉线程调度如果有人需要,可以先拿去,我过会再执行,没人需要,我继续执行)调用yield的时候锁并没有被释放。

5,参考资料