说说职场中的交流和沟通 [转发]

原文链接

关于职场的交流和沟通,记得我之前好像写过一些。来 Coinbase 已经有快两年了,有了不少的成长,尤其是在职场交流上。说起来,每个公司都有核心文化(core values),Coinbase 的四大核心文化之一,便是清楚有效的交流(clear communication)。所以能感觉到,这里的人,尤其是管理者,对交流和沟通的标杆是相当高的。文化和氛围这东西可意会但很难言传,所以我只能尽我最大努力简单说说自己的体会和经验吧。

交流大致分四种,一种是各种书面的文档、email,自己写好或者发出去,别人大部分时候是异步的阅读,然后有些情况会有评论(comment)或者回复;第二种是一对一的对话,这可能是面对面的交谈,也可能是 slack 这样的工具上的对话;第三种是组会,或者是 slack 群里面多人的讨论;最后一种是演讲(presentation),就是你一个人给大家讲。

先说一些适用于所有情况的基本准则。

首先就是从交流对象的角度去考虑话要怎么说。职场的交流沟通和朋友相处间的交流,最大的区别:交流是你工作的一部分。换句话来说,在职场你说话写字不是为了抒发情感,不是为了发泄感情,而是为了办好事情,让对方了解你想让他了解到的问题和情况,或者是你对一个问题的看法或想法。这里面可能和平时说话不大一样的地方,就是首先你要把对方作为中心,而不是你自己。你要说的,不是你想说的,或者你觉得正确的语序和方式;而是怎么说,会让对方会感兴趣,一下子就明白,并且印象深刻。

我遇到过组里的人,跟外组的人解释一个东西,从头到尾一二三,每条都对。但是外组的人听完了,虽然点头,但是其实这三条里,真正需要那个组的人注意或者帮忙的,就完全被弱化了,甚至不知道对方是不是真的会完全领会基于这三点,他该注意什么,该做什么。所以这种情况,后面加一句:这里你们可能尤其需要注意的,是xxx。这样就能极大强化对话的效果。

另外,说话不在多,不在快,而在准确切到重点上。事实上,尤其是口头的交流,你说多了、快了、除非对方已经知道大部分的内容,大部分你说的,都成了无可奈何的耳旁风。先把最重要的点说了,具体那些细节,等着别人来问再给更多,而不是一股脑儿都倒给对方,大部分时候效果会好很多。

如果是回答问题,确定你真的明白了对方想问的是什么再回答。开会的时候遇到一个人问了问题A,结果另一个人回答了问题B。如果你还不好插话,是不是特别着急?

还有的时候对方因为对一些具体细节不熟悉,问的问题甚至可能不是他真正困惑想问的问题。这种情况在上级问一个下级所属事务相关的问题,但是对那部分事务又不那么熟悉的时候尤为经常发生,这时候如果问题听起来似乎太简单或者太奇怪,你就要试着去推测对方是不是应该想了解另一个问题只是问的方式不对。推测完了先确认你推测的对不对:“您的问题答案是xxx,但我想您是不是想了解xxx的意思?” 这样的去确认,如果对方说不是,你那个答案就够了,那就算了。如果说是,这样,你才有机会回答了实际的问题。

演讲还是组会,说话的时候不要只盯着自己的电脑或者大屏幕,看看大家的表情和眼神,看看是不是已经云游方外了,还是有困惑的表情。如果你不能把大家的注意力带到你身上,那你说再多也只是背景噪音。

其次就是养成一个习惯,帮别人划重点。这个在书面交流中尤其重要。什么意思呢?如果是文档,你的 summary 或者 overview 就要确保假如别人没时间看完,他仍然能准确知道整个文档主要的中心思想。如果是 email,我发长的 email 一定都有两个要素:一个就是最前面的 TL;DR (too long, don’t read),一个就是 email 里一定会有 10% 左右的文字是黑体

因为职位需要,现在经常发周报,以及一些给高层或者整个大组的信件。我们都知道,长的信件除非是那种重要到他们不看会后悔的,大部分人可能看个标题很快就标注已读并存档。谁也没有时间和耐心去在你的信件里找有没有什么值得注意的。这个时候,前面的 TL;DR 确保是你用一句话描述了的大家绝对不能错过的内容的概述。如果需要更多讲解,加一句:see details below。这就帮助大家快速决定是不是有必要去读你的全文。

然后 email 主体再学会用黑体点出最重要的内容,这样别人如果只有30秒跳读你的信件,就会读所有的黑体部分。只要你重点没划错,你就帮你自己让别人没有错过你想传达的信息。

以前遇到别人说:我 email 里都写了啊,你自己没注意看。我会觉得,他说的很有道理。但是现在的我就不一定认同。如果你真的能把 email 写到帮别人划重点,并且划对,其实别人漏掉重要信息的可能性会极小。

最后说一说哪些是满分之外的那100分。

如果你刚和另一个人讨论一个问题有了一些方案、思路、想法、尤其是决定时,第一时间尽可能把讨论内容汇总群发 email 给或者 shared slack 给所有可能相关的人。这一点对于经常需要做决定的人尤其重要。否则你可能会遇到后面有另一个不同的决定,或者有些事情和你的决定好像有矛盾,然后你再去说:我和谁谁谁早谈过了,决定要怎么怎么。你没告诉到所有该告诉的人,谁知道你决定了什么啊。

但是要注意的是,群发的目的是让大家得到一致的信息(on the same page), 内容发出去前只要条件允许,请务必先让参与和你讨论的人过目确认,避免不必要的误解。而不是让和你讨论的人从群发消息上意识到你俩的理解有出入,然后炸了。好的处理,你先给参与讨论的人看了,说我这样发出去有问题吗,对方确认没有问题,这件事就很圆满。没有这一步,到时候那人说:我什么时候说xxx了,根本不是那个意思,那你就去吵吧。吵赢吵输,你都丢掉了一部分人的信任。

任何时候不要给你老板一个惊喜。在没有十足把握下,重要的或者敏感的东西发出去之前,先让老板看一下。他忙或者信任你说不用看了,那是另一回事。但是这样问一下,可以避免很多让你后悔的情况。甚至,哪些东西该由你说,哪些东西你就该等着你的老板先去说,尤其不要出格。

有两个以上人问你同一个问题,就不要反复口头回答或者私聊里回答。尤其是回答起来还比较费劲的问题,把答案记录下来放在一个共享的文档或者网页上,作为标准答案,不断去完善这个标准答案。下次再有人问、再有100个人问,给他发个答案链接就行。就不用去抱怨为什么大家总问你这个问题了。

同样,如果有多个人对你的某个设计、说法、方案有误解,就可能不是别人的理解问题,而是确实容易引起误会,这个时候,静下心来去看看怎么可以做到或者写到更好,而不要轻易觉得是自己找不到知己,或者别人智商不够。

先写这么多吧,职场的交流和沟通绝对是门大学问。初级的人能把事情说对明白(但别人能不能懂要看其理解力高低),中级的人能把大部分人都说懂,高级的人是通过交流和沟通把一整个团队、甚至别的团队结结实实拉到一起,达到自己想要的目的,把问题解决。当然,我也还一直在学习,共勉之。

最短路径算法

import java.util.PriorityQueue;

public class Dijkstra {

	/**
	 * 1.假设带权有向图G的顶点集合为V,起始点为V0。
	 * 2.初始S={V0},T=V-S={其余顶点},其中集合S表示已经计算出最短距离的顶点,T是还没计算的剩余顶点。
	 * 3.初始化V0到其余各点的距离,D(V0,Vi)代表V0到Vi的最短距离,按如下规则。
	 * 3.若V0可以直接到达某个顶点Vi,则将边的权值赋给(V0,Vi),否则D(V0,Vi)=∞。
	 * 5.从T中选取一个与S中顶点有关联(直接相连)且权值最小的顶点W(这里用到了贪心法思想),加入到S中。
	 * 6.以W作为中间点,若V0到T中某个顶点Vi距离变短,则修改D(V0,Vi)的值。 
	 * 7.重复5)和6)直到T为空。
	 * 
	 * @param src
	 * @param dst
	 * @param graph
	 * @param n
	 * @return
	 */
	public static int dijkstra(int src, int dst, int[][] graph, int n) {
		// 排序队列
		PriorityQueue<Node> pNodes = new PriorityQueue<>();
		int[] visitLog = new int[n + 1];
		// 记录访问过的点
		pNodes.add(new Node(src, 0));
		while (!pNodes.isEmpty()) {
			Node tNode = pNodes.poll();
			// 由于已经排序了 直接返回的就是最短路径
			if (tNode.node == dst) {
				return tNode.cost;
			}
			if (visitLog[tNode.node] == 1) {
				continue;
			}
			visitLog[tNode.node] = 1;
			for (int i = 0; i < n; i++) {
				// 可联通且没有遍历过
				if (graph[tNode.node][i] < 1000 && visitLog[i] != 1) {
					pNodes.add(new Node(i, tNode.cost + graph[tNode.node][i]));
				}
			}
		}
		return -1;
	}

	public static void main(String[] args) {
		int graph[][] = { { 0, 2, 3, 6, 1000, 1000 }, { 2, 0, 1000, 1000, 4, 6 }, { 3, 1000, 0, 2, 1000, 1000 },
				{ 6, 1000, 2, 0, 1, 3 }, { 1000, 4, 1000, 1, 0, 1000 }, { 1000, 6, 1000, 3, 1000, 0 } };// 地图

		System.out.println(Dijkstra.dijkstra(0, 3, graph, 6));
		System.out.println(Floyd.floyd(0, 3, graph, 6));
	}
}

/**
 * 
 * @author shichaopeng
 *
 *
 *
 *         邻接矩阵graph储存路径,同时最终状态代表点点的最短路径。如果没有直接相连的两点那么默认为一个很大的值(不要溢出)!而自己的长度为0.
 *         从第1个到第n个点依次加入图中。每个点加入进行试探是否有路径长度被更改。
 *         而上述试探具体方法为遍历图中每一个点(i,j双重循环),判断每一个点对距离是否因为加入的点而发生最小距离变化。如果发生改变,那么两点(i,j)距离就更改。
 *         重复上述直到最后插点试探完成。
 * 
 *         状态转移方程为: dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
 *         其中dp[x][y]的意思可以理解为x到y的最短路径。所以dp[i][k]的意思可以理解为i到k的最短路径dp[k][j]的意思可以理解为k到j的最短路径.
 */
class Floyd {

	/**
	 * 
	 * @param src
	 * @param dst
	 * @param graph
	 * @param n
	 * @return
	 */
	public static int floyd(int src, int dst, int[][] graph, int n) {
		int[][] r = new int[n][n];
		for (int i = 0; i < r.length; i++) {
			for (int j = 0; j < r.length; j++) {
				r[i][j] = graph[i][j];
			}
		}
		for (int k = 0; k < n; k++) { // 任意2点插入点 让后动态规划
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					r[i][j] = Math.min(r[i][j], graph[i][k] + graph[k][j]);
				}
			}
		}
		return r[src][dst];
	}

}

class Node implements Comparable<Node> {

	public int node;
	public int cost;

	public Node(int node, int cost) {
		super();
		this.node = node;
		this.cost = cost;
	}

	@Override
	public int compareTo(Node o) {
		return cost - o.cost;
	}

}

纪念刘和珍君

正因为他是和我们一样的普通人,所以他的行为格外英雄。 [李文亮医生 事件]


中华民国十五年三月二十五日,就是国立北京女子师范大学为十八日在段祺瑞执政府前遇害的刘和珍杨德群〔2〕两君开追悼会的那一天,我独在礼堂外徘徊,遇见程君〔3〕,前来问我道,“先生可曾为刘和珍写了一点什么没有?”我说“没有”。她就正告我,“先生还是写一点罢;刘和珍生前就很爱看先生的文章。”
这是我知道的,凡我所编辑的期刊,大概是因为往往有始无终之故罢,销行一向就甚为寥落,然而在这样的生活艰难中,毅然预定了《莽原》〔4〕全年的就有她。我也早觉得有写一点东西的必要了,这虽然于死者毫不相干,但在生者,却大抵只能如此而已。倘使我能够相信真有所谓“在天之灵”,那自然可以得到
更大的安慰,——但是,现在,却只能如此而已。
可是我实在无话可说。我只觉得所住的并非人间。四十多个青年的血,洋溢在我的周围,使我艰于呼吸视听,那里还能有什么言语?长歌当哭,是必须在痛定之后的。而此后几个所谓学者文人的阴险的论调,尤使我觉得悲哀。我已经出离愤怒了。我将深味这非人间的浓黑的悲凉;以我的最大哀痛显示于非人间,使它们快意于我的苦痛,就将这作为后死者的菲薄的祭品,奉献于逝者的灵前。

真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血。这是怎样的哀痛者和幸福者?然而造化又常常为庸人设计,以时间的流驶,来洗涤旧迹,仅使留下淡红的血色和微漠的悲哀。在这淡红的血色和微漠的悲哀中,又给人暂得偷生,维持着这似人非人的世界。我不知道这样的世界何时是一个尽头!
我们还在这样的世上活着;我也早觉得有写一点东西的必要了。离三月十八日也已有两星期,忘却的救主快要降临了罢,我正有写一点东西的必要了。

在四十余被害的青年之中,刘和珍君是我的学生。学生云者,我向来这样想,这样说,现在却觉得有些踌躇了,我应该对她奉献我的悲哀与尊敬。她不是“苟活到现在的我”的学生,是为了中国而死的中国的青年。
她的姓名第一次为我所见,是在去年夏初杨荫榆女士做女子师范大学校长,开除校中六个学生自治会职员的时候。〔5〕其中的一个就是她;但是我不认识。直到后来,也许已经是刘百昭率领男女武将,强拖出校之后了,才有人指着一个学生告诉我,说:这就是刘和珍。其时我才能将姓名和实体联合起来,心中却暗自诧异。我平素想,能够不为势利所屈,反抗一广有羽翼的校长的学生,无论如何,总该是有些桀骜锋利的,但她却常常微笑着,态度很温和。待到偏安于宗帽胡同〔6〕,赁屋授课之后,她才始来听我的讲义,于是见面的回数就较多了,也还是始终微笑着,态度很温和。待到学校恢复旧观〔7〕,往日的教职员以为责任已尽,准备陆续引退的时候,我才见她虑及母校前途,黯然至于泣下。此后似乎就不相见。总之,在我的记忆上,那一次就是永别了。

我在十八日早晨,才知道上午有群众向执政府请愿的事;下午便得到噩耗,说卫队居然开枪,死伤至数百人,而刘和珍君即在遇害者之列。但我对于这些传说,竟至于颇为怀疑。我向来是不惮以最坏的恶意,来推测中国人的,然而我还不料,也不信竟会下有残到这地步。况且始终微笑着的和蔼的刘和珍君,更何至于无端在府门前喋血呢?
然而即日证明是事实了,作证的便是她自己的尸骸。还有一具,是杨德群君的。而且又证明着这不但是杀害,简直是虐杀,因为身体上还有棍棒的伤痕。
但段政府就有令,说她们是“暴徒”!
但接着就有流言,说她们是受人利用的。
惨象,已使我目不忍视了;流言,尤使我耳不忍闻。我还有什么话可说呢?我懂得衰亡民族之所以默无声息的缘由了。沉默呵,沉默呵!不在沉默中爆发,就在沉默中灭亡。

但是,我还有要说的话。
我没有亲见;听说,她,刘和珍君,那时是欣然前往的。自然,请愿而已,稍有人心者,谁也不会料到有这样的罗网。但竟在执政府前中弹了,从背部入,斜穿心肺,已是致命的创伤,只是没有便死。同去的张静淑〔8〕君想扶起她,中了四弹,其一是手枪,立仆;同去的杨德群君又想去扶起她,也被击,弹从左肩入,穿胸偏右出,也立仆。但她还能坐起来,一个兵在她头部及胸部猛击两棍,于是死掉了。
始终微笑的和蔼的刘和珍君确是死掉了,这是真的,有她自己的尸骸为证;沉勇而友爱的杨德群君也死掉了,有她自己的尸骸为证;只有一样沉勇而友爱的张静淑君还在医院里呻吟。当三个女子从容地转辗于文明人所发明的枪弹的攒射中的时候,这是怎样的一个惊心动魄的伟大呵!中国军人的屠戮妇婴的伟绩,八国联军的惩创学生的武功,不幸全被这几缕血痕抹杀了。
但是中外的杀人者却居然昂起头来,不知道个个脸上有着血污……。

时间永是流驶,街市依旧太平,有限的几个生命,在中国是不算什么的,至多,不过供无恶意的闲人以饭后的谈资,或者给有恶意的闲人作“流言”的种子。至于此外的深的意义,我总觉得很寥寥,因为这实在不过是徒手的请愿。人类的血战前行的历史,正如煤的形成,当时用大量的木材,结果却只是一小块,但请愿是不在其中的,更何况是徒手。
然而既然有了血痕了,当然不觉要扩大。至少,也当浸渍了亲族;师友,爱人的心,纵使时光流驶,洗成绯红,也会在微漠的悲哀中永存微笑的和蔼的旧影。陶潜〔9〕说过,“亲戚或余悲,他人亦已歌,死去何所道,托体同山阿。”倘能如此,这也就够了。

我已经说过:我向来是不惮以最坏的恶意来推测中国人的。但这回却很有几点出于我的意外。一是当局者竟会这样地凶残,一是流言家竟至如此之下劣,一是中国的女性临难竟能如是之从容。
我目睹中国女子的办事,是始于去年的,虽然是少数,但看那干练坚决,百折不回的气概,曾经屡次为之感叹。至于这一回在弹雨中互相救助,虽殒身不恤的事实,则更足为中国女子的勇毅,虽遭阴谋秘计,压抑至数千年,而终于没有消亡的明证了。倘要寻求这一次死伤者对于将来的意义,意义就在此罢。
苟活者在淡红的血色中,会依稀看见微茫的希望;真的猛士,将更奋然而前行。
呜呼,我说不出话,但以此记念刘和珍君!

如何成事?-读冯唐的《成事》

1、有一个好的身体,身体是革命的本钱,事还没干,人就躺下了,怎么都成功不了,所以说我们要有好的身体,要把锻炼身体作为一种习惯,不知道该干什么的时候,看书和锻炼身体是最好的两个选择,当然冯唐也在书中写了应该如何锻炼身体,这个我们可以对照着练习,其实也很简单,每周集中锻炼三次,每次超过一个小时,要出汗,让后不断地减持下去就好。

2、要专一,冯唐写过《不二》这本书,其实不二这两个字说的就是专一这个道理,专一其实有很多种解释,其实就是一件事一件事的去做,专心致志的做事,不要吃纸碗里的看着锅里的,一次只做一件事情,完成了再去干第二件事情,养成习惯,离成事就近了一步。

3、第三点我觉得应该是埋头干事,只要不死就往死里干,事情做的多了,身体也好了,精神也好了,外面的世界关你屁事,关我屁事,好好干活就行,把手头的活干好了,该休息的时候放肆的休息。冯唐也说,其实现在很多的社会人,其实就是想的太多做的太少,嫌这嫌那,找各种借口,其实就是想偷懒,思想懈怠,要相成事就要埋头苦干。

4、大处着眼、小处着手。这八个字是书中提到最多的八个字,也是曾国藩成事的至理名言,通俗的讲,就是有目标有规划,要通盘考虑,完了以后就是埋头苦干,就是小处着手,从一件一件小事做起,一个一个的做,不能眼高手低。其实曾国藩能够打赢太平天国也是用的这个道理,曾国藩的湘军一开始打仗并不厉害,但是曾国藩就用笨方法,结硬寨打呆仗,就是跟你耗着,慢慢的跟你打,最终取得胜利。

5、要勤快。“百种弊病,皆从懒生”这也是曾国藩的原话,所有的事情都是懒惹的祸。任何时候不要懒,如果从小事开始变的勤快呢?先从早起开始,冯唐在书中说到早起不下十次之多,太阳都能早起,我们为什么不能早起,如果连早起的习惯都不能养成,连早起的毅力都没有,那么这个人肯定不能成事。所以一定要记住“百种弊病,皆从懒生”,勤快从早起开始。

6、另外还要养成一些好的习惯,比如读书、锻炼、定目标、反省等等,多去山里,多去图书馆、多去健身房,吃喝玩乐也要有,但一定要适度,人生短短几十年,如果真想成事,做出一番成就,要养成这些好的习惯,如果天天消耗、夜夜笙歌,一定不是一个能够成事的人。

洗牌算法

-- To shuffle an array a of n elements (indices 0..n-1):
for i from n−1 downto 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]

java 实现

import java.util.Arrays;
import java.util.Random;

public class Shuffle {

	public static void shuffle(int[] arr) {
		int i = arr.length;
		Random random = new Random();
		while (i > 1) {
			i = i - 1;
			int j = random.nextInt(i);
			int temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
		System.out.println(Arrays.toString(arr));
	}

	public static void main(String[] args) {
		int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
		for (int i = 0; i < 50; i++)
			shuffle(arr);
	}
}

运行50次结果

[7, 3, 0, 2, 9, 1, 8, 4, 6, 5]
[3, 2, 5, 9, 1, 6, 7, 0, 4, 8]
[7, 8, 6, 1, 4, 2, 0, 9, 5, 3]
[9, 3, 1, 7, 5, 6, 4, 8, 2, 0]
[5, 9, 0, 2, 1, 4, 7, 6, 3, 8]
[4, 8, 3, 9, 6, 1, 5, 0, 2, 7]
[0, 6, 9, 1, 3, 5, 4, 2, 7, 8]
[6, 3, 8, 4, 5, 2, 0, 9, 1, 7]
[8, 9, 3, 1, 4, 7, 6, 2, 0, 5]
[1, 8, 4, 7, 2, 3, 0, 5, 9, 6]
[9, 1, 3, 5, 0, 8, 6, 4, 2, 7]
[1, 7, 9, 4, 6, 3, 8, 0, 5, 2]
[0, 8, 4, 7, 3, 2, 6, 5, 9, 1]
[1, 7, 8, 9, 6, 5, 0, 4, 3, 2]
[5, 4, 1, 8, 0, 7, 3, 2, 9, 6]
[8, 6, 2, 0, 1, 5, 9, 3, 4, 7]
[5, 7, 4, 9, 0, 3, 6, 2, 1, 8]
[8, 9, 5, 4, 7, 0, 1, 3, 2, 6]
[2, 5, 6, 7, 3, 1, 4, 9, 0, 8]
[0, 7, 8, 2, 6, 5, 9, 1, 3, 4]
[4, 3, 6, 0, 5, 1, 2, 9, 8, 7]
[6, 1, 5, 8, 9, 4, 7, 0, 2, 3]
[9, 4, 0, 2, 5, 6, 3, 8, 7, 1]
[5, 2, 7, 0, 4, 3, 9, 6, 1, 8]
[4, 3, 1, 7, 9, 0, 6, 2, 8, 5]
[5, 8, 6, 1, 4, 9, 2, 0, 7, 3]
[3, 0, 2, 6, 1, 5, 8, 7, 9, 4]
[1, 6, 0, 4, 7, 3, 5, 9, 2, 8]
[5, 8, 6, 0, 2, 4, 7, 3, 9, 1]
[8, 7, 3, 6, 4, 1, 0, 9, 2, 5]
[9, 0, 7, 1, 5, 8, 4, 3, 6, 2]
[0, 4, 9, 7, 8, 1, 6, 5, 2, 3]
[5, 0, 4, 2, 1, 7, 9, 8, 3, 6]
[7, 2, 8, 3, 5, 4, 1, 0, 6, 9]
[2, 6, 4, 8, 0, 5, 9, 7, 1, 3]
[0, 2, 9, 7, 8, 6, 1, 4, 3, 5]
[6, 4, 1, 2, 9, 7, 5, 3, 8, 0]
[3, 2, 4, 0, 5, 9, 8, 1, 6, 7]
[9, 0, 8, 7, 6, 2, 3, 4, 1, 5]
[4, 1, 5, 3, 8, 9, 0, 6, 2, 7]
[8, 5, 6, 0, 2, 4, 7, 3, 1, 9]
[1, 4, 9, 6, 3, 2, 8, 7, 0, 5]
[9, 5, 6, 2, 0, 7, 1, 3, 4, 8]
[1, 8, 3, 6, 4, 5, 7, 0, 9, 2]
[8, 3, 7, 5, 1, 9, 0, 2, 4, 6]
[2, 0, 6, 4, 5, 1, 9, 7, 8, 3]
[9, 6, 1, 2, 4, 8, 3, 5, 7, 0]
[6, 3, 4, 0, 2, 1, 8, 9, 5, 7]
[2, 9, 1, 3, 5, 6, 4, 8, 7, 0]
[3, 5, 7, 1, 6, 0, 8, 9, 4, 2]

BackOff重试算法

可以使用斐波那契数列计算重试时间,也可以使用指数补偿计算重试时间。

定义一个接口

@FunctionalInterface
public interface ExponentialBackOffFunction <T> {
	T execute();
}

定义重试工具类

import static java.util.Arrays.asList;

import java.net.SocketTimeoutException;
import java.util.List;

import javax.net.ssl.SSLHandshakeException;

import lombok.extern.log4j.Log4j;

@Log4j
public final class ExponentialBackOff {
	
	private static final int[] FIBONACCI = new int[] { 1, 1, 2, 3, 5, 8, 13 };
	private static final List<Class<? extends Exception>> EXPECTED_COMMUNICATION_ERRORS = asList(
			SSLHandshakeException.class, SocketTimeoutException.class);

	private ExponentialBackOff() {
	}

	// E(c) = Math.pow(2, c) - 1
	// 考虑到补偿时间的均匀分布,补偿时间的数学期望是所有可能性的平均值。
	// 也就是说,在c次冲突之后,补偿时隙数量在 [0,1,...,N] 中,其中 [公式] E(c) = Math.pow(2, c) - 1
	// 则补偿时间的数学期望 E(c) = (Math.pow(2, c) - 1)/2
	public static long getWaitTimeExponential(int attempt) {
		double waitTime = (Math.pow(2, attempt) - 1) / 2;
		return Math.round(waitTime * 100);
	}
	
	// 这个地方使用斐波那契数去增加重试时间
	public static long getWaitTimeDefault(int attempt) {
		return FIBONACCI[attempt] * 100;
	}

	public static <T> T execute(ExponentialBackOffFunction<T> fn) {
		for (int attempt = 0; attempt < FIBONACCI.length; attempt++) {
			try {
				return fn.execute();
			} catch (Exception e) {
				handleFailure(attempt, e);
			}
		}
		throw new RuntimeException("Failed to communicate.");
	}

	private static void handleFailure(int attempt, Exception e) {
		if (e.getCause() != null && !EXPECTED_COMMUNICATION_ERRORS.contains(e.getCause().getClass()))
			throw new RuntimeException(e);
		doWait(attempt);
	}

	private static void doWait(int attempt) {
		try {
			long sleepTime = getWaitTimeExponential(attempt);
			System.out.println("attempt " + attempt + " sleep " + sleepTime);
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
}

测试案例

public class Test {
	public static void main(String[] args) {
		ExponentialBackOff.execute(new Work());
	}
}

class Work implements ExponentialBackOffFunction<String> {

	@Override
	public String execute() {
		int a = 5 / 0;
		return a + "";
	}
}

运行结果

使用指数补偿:
attempt 0 sleep 0
attempt 1 sleep 50
attempt 2 sleep 150
attempt 3 sleep 350
attempt 4 sleep 750
attempt 5 sleep 1550
attempt 6 sleep 3150
使用斐波那契数列
attempt 0 sleep 100
attempt 1 sleep 100
attempt 2 sleep 200
attempt 3 sleep 300
attempt 4 sleep 500
attempt 5 sleep 800
attempt 6 sleep 1300

微服务编排框架

发现一个优秀的微服务编排框架:zeebe

微服务核心研究之–编排

当一个系统采用了微服务架构后,会拆分成很多新的微服务,但原有的业务可能还是没有变化,如何在微服务架构下实现原有的业务?相对于传统架构,微服务架构下更需要通过各微服务之间的协作来实现一个完整的业务流程,可以说服务编排是微服务架构下的必备技能。但是,编排涉及到RPC、分布式事务等等,编排的质量不能仅仅取决于老师傅的手艺,需要有完善的编排框架来支撑。

关于微服务的组合(协调):
编制(Orchestration)—— 面向可执行的流程:通过一个可执行的流程来协同内部及外部的服务交互。通过中心流程来控制总体的目标,涉及的操作,服务调用顺序。
编排(Choreography)—— 面向合作:通过消息的交互序列来控制各个部分资源的交互。参与交互的资源都是对等的,没有集中的控制。

哲学家就餐问题 [go/java 实现练习并发编程]

java

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

class Philosopher implements Runnable{
	private final String name;
	private final ReentrantLock left;
	private final ReentrantLock right;
	private final AtomicInteger hunger = new AtomicInteger(3);
	public Philosopher(String name, ReentrantLock left, ReentrantLock right) {
		this.name = name;
		this.left = left;
		this.right = right;
	}
	@Override
	public void run() {
		while (this.hunger.get() > 0) {
			System.out.println(name + " Hungry");
			this.left.lock();
			this.right.lock();
			System.out.println(name + " Eating");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			this.right.unlock();
			this.left.unlock();
			System.out.println(name + " Thinking");
			this.hunger.decrementAndGet();
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}	
}

public class DiningPhilosopher {
	public static void main(String[] args) {
		ExecutorService executor = Executors.newCachedThreadPool();
		String[] philosophers = new String[] {"Mark", "Russell", "Rocky", "Haris", "Root"};
		ReentrantLock fork0 = new ReentrantLock();
		ReentrantLock forkLeftLock = fork0;
		List<Philosopher> philosopherList = new ArrayList<Philosopher>();
		for(int i=1;i<philosophers.length;i++) {
			String name = philosophers[i];
			ReentrantLock forkRightLock = new ReentrantLock();
			philosopherList.add(new Philosopher(name, forkLeftLock, forkRightLock));
			forkLeftLock = forkRightLock;
		}
		philosopherList.add(new Philosopher(philosophers[0], fork0, forkLeftLock));
		for (Philosopher philosopher : philosopherList) {
			executor.submit(philosopher);
		}
		executor.shutdown();
	}
}

go

package main

import (
	"hash/fnv"
	"log"
	"math/rand"
	"os"
	"sync"
	"time"
)

// 初始化5个人
var ph = []string{"Mark", "Russell", "Rocky", "Haris", "Root"}

const hunger = 3                // 每个哲学家吃几次饭
const think = time.Second / 100 // 思考时间
const eat = time.Second / 100   // 吃饭时间

var fmt = log.New(os.Stdout, "", 0)

var dining sync.WaitGroup

func diningProblem(phName string, dominantHand, otherHand *sync.Mutex) {
	fmt.Println(phName, "Seated")
	h := fnv.New64a()
	h.Write([]byte(phName))
	rg := rand.New(rand.NewSource(int64(h.Sum64())))
	rSleep := func(t time.Duration) {
		time.Sleep(t/2 + time.Duration(rg.Int63n(int64(t))))
	}
	for h := hunger; h > 0; h-- {
		fmt.Println(phName, "Hungry")
		dominantHand.Lock() // 获取资源
		otherHand.Lock()
		fmt.Println(phName, "Eating")
		rSleep(eat)
		dominantHand.Unlock() // 释放资源
		otherHand.Unlock()
		fmt.Println(phName, "Thinking")
		rSleep(think)
	}
	fmt.Println(phName, "Satisfied")
	dining.Done()
	fmt.Println(phName, "Left the table")
}

func main() {
	fmt.Println("Table empty")
	dining.Add(5)
	fork0 := &sync.Mutex{}
	forkLeft := fork0
	for i := 1; i < len(ph); i++ {
		forkRight := &sync.Mutex{}
		go diningProblem(ph[i], forkLeft, forkRight)
		forkLeft = forkRight
	}
	go diningProblem(ph[0], fork0, forkLeft)
	dining.Wait() // 等待结束
	fmt.Println("Table empty")
}

云在青天水在瓶

忙里偷闲终于把大明王朝1566看完了,对政治和经济更加敬畏。分享那些让人听来振聋发聩的语录。

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.裕王:大明朝谁是贤臣?嘉靖:没有谁是真正的贤臣,贤时用之,不贤黜之。