1 Algorithm
你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。
你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。
示例:
输入: 4
输出: false
解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛;
因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。
class Solution {
public boolean canWinNim(int n) {
return n%4!=0;
}
}
2 Review
为什么不用 ZooKeeper 做服务发现
3 Tip
GIT常用命令总结
1、gitignore规则不生效
.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。
解决方法就是先把本地缓存删除(改变成未track状态),然后再提交:
git rm -r --cached .
git add .
git commit -m ‘update .gitignore’
2、git忽略某个指定的文件(不从版本库中删除)
执行命令如下:
git update-index --assume-unchanged config.conf
用git status查看一下,已经得到了自己想要的效果
3、git取消忽略某个指定的文件
git update-index --no-assume-unchanged config.conf
4、将当前版本回退到上一个版本,命令如下:
git reset --hard HEAD^
5、 回退到上两个版本
git reset – hard HEAD^^
6、回退到指定版本
git log //显示从最近到最远的提交日志
git reset --hard commit_id //回退到指定版本
7、查看命令历史
git reflog
8、拉取暂存区文件并将其替换成工作区文件
gitcheckout--
9、跟踪取消,即把文件从git中拿出来,不再进行版本跟踪,但保留工作区的文件。
git rm - - cached filename
10、查看工作区和版本库里面最新版本的区别
git diff HEAD – readme.txt
git diff命令比较的是工作目录中当前文件与暂存区快照之间的差异,也就是修改之后还没有暂存起来的变化内容
11、将工作去的内容放入版本库的暂存区
git add readme.txt
12、将暂存区的内容提交到当前分支
git commit -m “git tracks changes”
13、显示工作目录和暂存区的状态
git status
14、删除一个文件
git rm test.txt
15、从远程库克隆项目
git clone 项目地址
16、创建分支,然后切换到分支
git checkout -b dev
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
git branch dev
git checkout dev
17、查看当前分支
git branch
git branch命令会列出所有分支,当前分支前面会标一个*号
18、git merge命令用于合并指定分支到当前分支
git merge dev
19、删除本地分支
git branch -d dev
20、删除远程dev分支
git push origin :dev
21、切换分支
git checkout
22、查看远程库的信息
git remote 或 git remote -v
23、推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
git push origin master
如果要推送其他分支,比如dev,就改成:
git push origin dev
24、拉取分支
git pull
4 Share
Java内存模型总结
- 为什么定义Java内存模型?现代计算机体系大部是采用的对称多处理器的体系架构。每个处理器均有独立的寄存器组和缓存,多个处理器可同时执行同一进程中的不同线程,这里称为处理器的乱序执行。在Java中,不同的线程可能访问同一个共享或共享变量。如果任由编译器或处理器对这些访问进行优化的话,很有可能出现无法想象的问题,这里称为编译器的重排序。除了处理器的乱序执行、编译器的重排序,还有内存系统的重排序。因此Java语言规范引入了Java内存模型,通过定义多项规则对编译器和处理器进行限制,主要是针对可见性和有序性。
- 三个基本原则:原子性、可见性、有序性。
- Java内存模型涉及的几个关键词:锁、volatile字段、final修饰符与对象的安全发布。其中:第一是锁,锁操作是具备happens-before关系的,解锁操作happens-before之后对同一把锁的加锁操作。实际上,在解锁的时候,JVM需要强制刷新缓存,使得当前线程所修改的内存对其他线程可见。第二是volatile字段,volatile字段可以看成是一种不保证原子性的同步但保证可见性的特性,其性能往往是优于锁操作的。但是,频繁地访问 volatile字段也会出现因为不断地强制刷新缓存而影响程序的性能的问题。第三是final修饰符,final修饰的实例字段则是涉及到新建对象的发布问题。当一个对象包含final修饰的实例字段时,其他线程能够看到已经初始化的final实例字段,这是安全的。
- happens-before 先行发生原则
1).程序次序规则:在一个线程内,按照程序代码顺序,在前面的操作先行发生于在后面的操作。准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。
(2).管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而"后面"是指时间上的先后顺序。
(3).volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的"后面"同样是指时间上的先后顺序。
(4).线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
(5).线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
(6).线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
(7).对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始 - Happens-Before的1个特性:传递性。
- Java内存模型底层怎么实现的?主要是通过内存屏障(memory barrier)禁止重排序的,即时编译器根据具体的底层体系架构,将这些内存屏障替换成具体的 CPU 指令。对于编译器而言,内存屏障将限制它所能做的重排序优化。而对于处理器而言,内存屏障将会导致缓存的刷新操作。比如,对于volatile,编译器将在volatile字段的读写操作前后各插入一些内存屏障。