有这样一个类 ZeroEvenOdd,相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:
线程 A 将调用 zero(),它只输出 0 。
线程 B 将调用 even(),它只输出偶数。
线程 C 将调用 odd(),它只输出奇数。
每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506... ,其中序列的长度必须为 2n。
输入:n = 2
输出:"0102"
说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),最后一个线程调用odd()。正确的输出为 "0102"。
线程同步问题,可以使用锁或者信号量解决。
- 解法一:Lock 和 Condition
private static class ZeroEvenOdd1 {
private final Lock lock = new ReentrantLock();
private final Condition evenCondition = lock.newCondition();
private final Condition oddCondition = lock.newCondition();
private final Condition zeroCondition = lock.newCondition();
private int n;
private int current = 1;
// 0 refers zero, 1 refers odd, 2 refers even
private int state = 0;
public ZeroEvenOdd1(int n) {
this.n = n;
}
// printNumber.accept(x) outputs "x", where x is an integer.
public void zero(IntConsumer printNumber) throws InterruptedException {
lock.lock();
try {
while (current <= n) {
if (state != 0) {
zeroCondition.await();
}
printNumber.accept(0);
if ((current & 1) == 0) {
state = 2;
evenCondition.signal();
} else {
state = 1;
oddCondition.signal();
}
zeroCondition.await();
}
oddCondition.signal();
evenCondition.signal();
} finally {
lock.unlock();
}
}
// 偶数
public void even(IntConsumer printNumber) throws InterruptedException {
lock.lock();
try {
while (current <= n) {
if (state != 2) {
evenCondition.await();
} else {
printNumber.accept(current++);
state = 0;
zeroCondition.signal();
}
}
} finally {
lock.unlock();
}
}
// 奇数
public void odd(IntConsumer printNumber) throws InterruptedException {
lock.lock();
try {
while (current <= n) {
if (state != 1) {
oddCondition.await();
} else {
printNumber.accept(current++);
state = 0;
zeroCondition.signal();
}
}
} finally {
lock.unlock();
}
}
}
- 解法二:Semaphore
private static class ZeroEvenOdd2 {
private final Semaphore zeroSemaphore = new Semaphore(1);
private final Semaphore evenSemaphore = new Semaphore(0);
private final Semaphore oddSemaphore = new Semaphore(0);
private int n;
public ZeroEvenOdd2(int n) {
this.n = n;
}
// printNumber.accept(x) outputs "x", where x is an integer.
public void zero(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
zeroSemaphore.acquire();
printNumber.accept(0);
if ((i & 1) == 0) {
evenSemaphore.release();
} else {
oddSemaphore.release();
}
}
}
public void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 2; i <= n; i += 2) {
evenSemaphore.acquire();
printNumber.accept(i);
zeroSemaphore.release();
}
}
public void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i += 2) {
oddSemaphore.acquire();
printNumber.accept(i);
zeroSemaphore.release();
}
}
}
Follow these simple rules and you’ll become a Git and GitHub master 遵循这些规范,你就会成为 Git 大师。
作者提出了三条建议:
- 为每个新项目创建 Git 仓库
- 为每个新需求创建新分支
- 使用 pull request 合并代码到 master 分支
点评:Git 是非常强大的版本控制工具,每个程序员都该熟练掌握。
《高效阅读法》(levarage reading)讲了许多不一样的读书方法。读书不一定要从头开始完整读一遍,只读对自己有用的、感兴趣的地方,无关紧要的内容一律跳过,设定读书的时间限制,比如两小时读完,这样读书速度就提升了一大截。仅仅读了还不够,要运用到生活中,读以致用。 最有效的投资就是自我投资,读书是最好的自我投资。
阿里技术专家的一篇分享,对于技术和业务讲得非常中肯。下面是作者的几个观点:
- 业务先赢是技术第一要务。技术人员首要任务是先把业务支持好,在这个前提下,再来讲技术沉淀和技术红利。
- 理解业务有助于你做技术决策去驱动业务,有助于你对资源的优先级做判断,而且还有助于提升你的研发效能。
- 理解业务更多是理解了运营决策背后的原因,理解了网站各个角色的诉求和痛点,理解了自己做的产品和项目对业务的价值和影响。
- 技术人的三大支柱:业务理解、项目管理和专业技术。一个不理解业务的研发,和流水线的工人是没有很大的区别的。
- 技术人员不一定要去这么深入理解业务或者成果出在业务上,对技术很感兴趣的同学而且有抓手的同学,就安心地去专研技术并取得结果就好,注意要取得结果,不能是说不清楚的东西。
- 对于技术上没有鲜明特色的同学,或者有技术深度但是暂时想不到什么技术挖掘点的同学,不妨去多看看业务,寻找技术驱动业务的机会。