邱永臣与世界(V)

1.大师又向陈达透露了一个秘密,他问陈达:“你知道为什么自古以来,爱情故事的主角往往是王子和公主?”还没等陈达想出个明白,大师就揭露了谜底:“那是因为古时候只有王子和公主才有时间、精力和金钱谈谈爱情,其他人没这个条件。就像摩西带领四十万人逃出埃及,那四十万人不都是奴隶嘛?精力用在建设世界级古文明,何来时间谈爱情,引用一句大聪的名言:’从幸福家庭出生的孩子,对爱情的憧憬,那是没事吃饱了撑’。”

2.“她出生时爷爷是老领导,你出生时爷爷是农民,没法比”,来自巴蜀的大师听到此话,很无奈:“读书时你就喜欢诋毁我,现在还是,死性不改啊”

3.当年西部大开发、淘金热,要抓“猪仔”修铁路的时候,大批大批福建人乘坐轮船偷渡到美国,到旧金山,落地生根,建立斧头帮,直到现在,福建仍旧有许多华侨村。
以前知道福建有钱人多,移民的也多,羡慕,现在了解他们的历史,反倒为他们感伤起来,也不知道第一批移民受到了怎样的虐待。

邱永臣与世界(U)

1.入夜后,陈达总是陷入无尽的恐惧,空荡荡的房间里,只有硬盘的声音在回响,听多了会耳鸣。总觉得心里有块压抑的大石头,无法呼气,无法吸气,眼前模糊,失去嗅觉失去味觉,失去一切。

2.放牛班的春天,身在放牛班,向往春天。

3.上一次,陈达指出任务简单难度低,被人说成是嚣张。打那以后,陈达遇到问题,无论大小巨细,均会竭尽所能,极力渲染其难度,增益自己所不能,从此再没有人说他嚣张,而是说:“这小伙子,挺圆滑世故的”。陈达心想,哎呀,这中华传统美德中庸之道,我也算是跨过了它的门槛入门了,物极必反,乐极生悲,否极泰来,什么东西多了,总会变个味。

4.薛定谔方程,该方程奇怪之处在于,方程和方程的解都在解释物理世界,比如谁家的猫掉进坑里了,比如谁家丈夫精神出轨了,比如相对论,比如量子力学,总而言之,言而总之,薛定谔方程可以解释世间万事万物,唯一遗憾的是方程没有真正意义上的解。

Java多线程深入总结

零、前言

多线程是一块比较基础的知识,先前呢,吃瓜群众对它的接触仅限于使用,底层原理略知一二,无奈无法拿出来给其它吃瓜群众吹水,所以这次深入研究一番,得此笔记图。

一、脑图笔记

(大图慎入)

Read More

用Flow.CI搭建CI/CD

一、前言

在上一篇文章里,我使用Travis来做自动部署,链接在此:Travis构建Google App Engine的CI/CD)。Travis使用起来挺方便,只不过它仅支持github。

不希望某些关键代码被人看到,而且,大部分代码托管在bitbucket上,挪移代码仓库不方便,考虑下来,只能找一个支持自定义代码仓库的CI平台了。
调研下来,有CodeShip/JenKins/Flow.Ci等几个工具。

CodeShip支持Bitbucket,只不过每个月只能构建100次。
JenKins是开源的,可以自己部署到服务器上,公司内部用的就是它,不过我不太喜欢JenKins,因为它的icon不甚好看…
Flow.Ci是国产开源的工具,现在(2018-02-13)还是Beta测试版本,类似Jenkins,自己部署,我选的就是它。

Read More

Travis构建Google App Engine的CI/CD

一、前言

这篇文档的目的,是记录我使用Travis构建持续集成与自动部署的过程中踩到的坑,当做学习总结。

二、Travis

Travis是个CI/CD的平台。

简单地理解,你可以认为它给你提供了一台服务器。你往服务器上放一个CI/CD相关的脚本,脚本监控Github代码变更,调用Maven编译,并部署进你购买的服务器。

(注:我购买的服务器是谷歌云,它拥有App Engine,对外提供接口,使得Travis能调用接口进行部署。)

Read More

Http的POST请求

项目系统经常需要调用外部系统的接口,使用http的post请求方式来获得数据,陈达经常搞混post的请求方式,在这里记一下。

Post

post请求,类似于get请求,拥有状态行、请求头header和请求体body。

状态行

状态行比较简单,一般都长下面的模样:

1
<methon> <url> <version>

比如:

1
POST www.iloveqyc.com HTTP/1.1

请求头

请求头则是用来说明解释本请求的上下文,比如请求头里可以指定cookie、UA等信息。在这里主要关注Content-Type这个信息,它指定了请求体body里面数据的编码方式。

编码方式是什么意思呢?陈达要给远方的服务器发消息,消息内容塞在body里面,服务器收到消息后怎么知道消息体里面是什么东西呢?把消息体当做key-value?当做json串?当做xml?服务器做不到啊~

所以在使用Post的时候,需要在Content-Type里指明消息体body的编码方式。

消息体

消息体主要就是用来承载该post请求要发送的内容,其编码方式可以用消息头header里的Content-Type指定。

Content-Type

application/x-www-form-urlencoded

这种方式很常见,一般页面上的表格都是用x-www-form-urlencoded的方式post,body里的提交值按照key1=value1&key2=value2进行排列,且进行url转码(比如转成unicode)。

这种方式也是目前项目用的post方式。

multipart/form-data

这种方式主要是用来上传文件,在body里面指定文件类型,和x-www-form-urlencoded一样,是2种最常用的方式。

application/json

使用这种方式,你可以在body里直接贴json字符串,而不用写键值对。(有的人不直接用application/json,而是使用x-www-form-urlencoded,在键值对的value里面写json,这倒也是一种方法)

text/xml

顾名思义,这种方式提交的是xml,不过xml太臃肿,用的比较少

利用AQS实现同步组件

AQS(AbstractQueueSynchronizer),抽象队列同步器,是jdk提供的一种用来自定义实现同步组件的工具,java并发中的ReentrantLock/CountDownLatch/Semaphore也都是继承了它而实现。

现在陈达想要用它来实现一个自己的同步器,功能是限制同一时间内只有2个线程才能获取锁。

总的思路是同步组件QycLock实现Lock接口,实现加锁lock与解锁unlock。QycLock内部集成了一个继承自AQS的自定义同步器QycSync,主要的同步逻辑均在QynSync上,QycLcok仅是个包装。

QycSync继承自AQS,便是拥有了同步状态和同步队列,把初始状态值设为2,一个线程获取同步状态后,用CAS的方式让状态值-1,释放同步状态后,用CAS的方式让状态值+1。

QycSync代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.iloveqyc.service.test.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
* Project: rcs-web
* PACKAGE_NAME: com.iloveqyc.service.test.lock
* Date: 2017/12/3
* Time: 下午2:20
*
* @author qiuyongchen David
* <p>
* Usage: 同步器
*/
public class QycLock implements Lock {

private QycSync qycSync = new QycSync(2);

@Override
public void lock() {
qycSync.acquireShared(1);
}

@Override
public void lockInterruptibly() throws InterruptedException {

}

@Override
public boolean tryLock() {
return false;
}

@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}

@Override
public void unlock() {
qycSync.releaseShared(1);
}

@Override
public Condition newCondition() {
return null;
}

static class QycSync extends AbstractQueuedSynchronizer {

QycSync(int count) {
if (count <= 0) {
throw new RuntimeException();
}
setState(count);
}

@Override
protected int tryAcquireShared(int arg) {
for (;;) {
int currentState = getState();
int newState = currentState - 1;
if (newState < 0) {
System.out.println(Thread.currentThread().getName() + "到达时同步状态已经小于0,将会在同步队列中调用sun.misc.Unsafe.park,进入等待状态");
return newState;
}
boolean isSuccess = compareAndSetState(currentState, newState);
if (!isSuccess) {
System.out.println(Thread.currentThread().getName() + "尝试获取锁失败, 同步状态currentState预期为" + currentState + ", 实际不是");
continue;
}
return newState;
}
}

@Override
protected boolean tryReleaseShared(int arg) {
int currentState = getState();
int newState = currentState + 1;
return compareAndSetState(currentState, newState);
}
}
}

QycThread代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.iloveqyc.service.test.lock;

/**
* Project: rcs-web
* PACKAGE_NAME: com.iloveqyc.service.test.lock
* Date: 2017/12/3
* Time: 下午2:47
*
* @author qiuyongchen David
* <p>
* Usage: xxx
*/
public class QycThread implements Runnable {

private QycLock qycLock;

public QycThread(QycLock qycLock) {
this.qycLock = qycLock;
}

@Override
public void run() {
qycLock.lock();
System.out.println(Thread.currentThread().getName() + "成功获取了锁!即将带着锁睡眠60s");
try {
Thread.sleep(60000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "睡眠60s结束,即将释放锁");
qycLock.unlock();
}

}

main方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.iloveqyc.service.test.lock;

/**
* Project: rcs-web
* PACKAGE_NAME: com.iloveqyc.service.test.lock
* Date: 2017/12/3
* Time: 上午9:52
*
* @author qiuyongchen David
* <p>
* Usage: xxx
*/
public class QycTest {
public static void main(String[] args) {
QycLock lock = new QycLock();
for (int i = 0; i < 10; i++) {
Thread t = new Thread(new QycThread(lock));
t.setName(String.valueOf(i));
t.start();
}
}
}

邱永臣与世界(T)

1.那遥远的小山坡,那芳华自赏,那林中的小鸟。

2.意识形态覆盖下,单独的人性消失殆尽。陈达终于明白:巴比伦人流放以色列人,欧洲侵略者贩卖非洲奴隶,纳粹洗劫欧洲犹太人并把他们关进集中营,日本屠杀无辜居民,是一种集体的力量作祟,用大师的话来说,是群的力量。

3.在家宅了2天,一个人的日子虽然孤单一点,可是也很惬意,不用担惊受怕,也不用积极表现自我,一切烦心的事情,都让它随风而去吧。

4.悲伤逆流成河……中文真有意思,有些词你不处在它的语境里就体会不到滋味,比如“心痛”“呼吸不过来”“大脑一片空白”等

5.据大师散布的谣言,文革时其妈妈被打断了左手,其爸爸一直不让孩子寻仇,觉得以毒攻毒没有意义,而大师总是不忘家仇国恨,宣扬快意洒脱。

6.软件开发这玩意,规模大了之后,往往会变成前途是光明的,道路是曲折的,一两个月都开发不完。

7.这两场比赛不仅终结了80后90后的青春,还毁掉了他们的自尊心和想象力,就跟中国足球一样。

8.领域驱动、界限上下文,这些概念不就是神棍子大师所说“四海之内皆兄弟”的群论吗?群内群外、相爱相杀、你死我活……

9.谭咏麟在《迟来的春天》里唱:“面对的彷佛多麽渺茫,更加上这道墙,围着我纵有热情难再开放。”又想到王菲在《蝴蝶》里唱:“蝴蝶飞不过沧海,有谁忍心责怪。”记者的闪光灯咔咔地在王祖贤面前闪,而据调查,98.765%的听众没有注意到齐秦的下一句歌词“外面的世界很无奈”。

10.大师嘲笑陈达:“你看你,周围的朋友同事个个身家千万,只有你,德智体美三好打工仔,除此之外啥都没有”。
陈达说:“我这不是生不逢时嘛?要逢时了,拆它几百套,也财务自由了”

11.过去的记忆使我伤心使我难忘,随它去吧,就让它随风而去吧。