Lenshood

Software Developer @ThoughtWorks

分布式锁

在传统单体应用中,我们用锁来保证非幂等操作在并发调用时不会产生意外的结果。最常见的应用场景应该就是 MySQL 用锁保证写表时不会重复写入或读表时读到脏数据。

进入微服务时代,整个业务系统可能是由数十个不同的服务节点组成,每个服务节点还包括多个实例确保高可用。在这样的环境下,一个写请求可能会由于负载均衡通过不同的服务实例操作数据,大多 NoSQL 实现为了并发性而牺牲了事务,则可能导致数据的正确性被破坏。这时如果有一个全局锁来对不同服务的操作进行限制,那么会一定程度解决上述问题。(对于复杂场景还需要采用分布式事务来处理回滚等等。)

与本地锁类似,分布式锁也是独立的对象,只不过存储在独立的节点上。最朴素的方法是在数据库中存储一段数据,以此为锁对象,存在则表示锁已被其他服务获取,不存在则表示可获取。当然此方案完全没考虑过死锁、可重入性等问题,而且如果是用关系型数据库来实现,则无法支撑高并发的场景。因此通常我们会采用 Redis、ZooKeeper 等方案来实现,并对锁代码进行一定设计,增加超时、重试等等功能。

Read more »

不可变集合

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");

class Foo {
final ImmutableSet<Bar> bars;
Foo(Set<Bar> bars) {
this.bars = ImmutableSet.copyOf(bars); // defensive copy!
}
}
Read more »

排序

示例

1
assertTrue(byLengthOrdering.reverse().isOrdered(list));

简述

Ordering是 Guava 的“流式”Comparator类。它能够用于构建复杂的比较器,并且能应用于集合对象上。

一个Ordering实例的核心仅仅是一个特殊的Comparator实例。Ordering简单的取用一些依赖Comparator的静态方法(例如 Collections.max)将之改造为实例方法。此外,Ordering类还提供了链式方法来改进、增强现有的比较器。

Read more »

使用和避免使用 null

"null 烂透了“ - Doug Lea "这是我犯得值 10 亿刀的错误" - Sir C. A. R. Hoare 提到他发明的 null 时如是说

null的粗心使用会导致各种各样令人难以置信的错误。对 Google 的基础代码进行研究后,我们发现大约 95% 的集合中都不应有任何 null 值,如果对 null 快速失败而不是默默地接受,便会对开发者有所帮助。

此外,null 也会产生令人不悦的模糊情况。通常很少有能准确的揣摩到返回null值原本意义场景,例如,当 Map.get(key)返回null 时,一种可能是 key 对应的值本来就是null,而另一种情况则是该 key 并不存在。Null 能代表失败,能代表成功,能代表几乎任何事。如果能用其他的值来代替null,会使表意更加清晰。

即便如此,有些时候使用 null 仍旧是正确合理的。从内存占用和速度角度讲,null 非常划算,而且不可避免的会在对象数组中使用。然而,相较于库代码,在应用代码中, null 是造成逻辑困扰、难以理解的 bug 以及令人不悦的模糊的主要来源。例如,当 Map.get 返回 null 时,null 可能代表值不存在,或者值存在且等于 null。最要命的,null 不会对他所代表的的意义给出任何提示。

由于上述原因,大多数 Guava 工具都设计为只要能找到 null 的替代方案,就对 null 采取快速失败处理,不允许使用 null。此外,Guava 提供了许多工具,让你在必须使用 null 的时候能更简单,也能帮助你避免使用 null

Read more »

并发编程是 Java 编程的基础,同时也是提升效率,改善性能表现的利器。说到并发,就一定会说到同步,synchronized关键字是 Java 中关于同步最基础的设计,它能够简单明确的提供对变量、代码块、方法、类的同步支持。我们大都知道,同步能够为代码提供原子性,但有时我们会忽略,同步还有一个重要的作用,就是提供了代码的可见性。

下文将从两个方面,以 Java 为例简述同步带来的原子性和可见性,并在可见性部分引出了经常令 Java 程序员困惑的 volatile关键字。

Read more »

There's a very simple routine in the book: Clean Code, Chapter 6, page 96

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
public class Square {
public Point topLeft;
public double side;
}

public class Rectangle {
public Point topLeft;
public double height;
public double width;
}

public class Circle {
public Point center;
public double radius;
}

public class Geometry {
public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException
{
if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * s.side;
}
else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
}
else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException();
}
}
As a OO programer, what a ugly code! That code are totally no object-oriented, and use such a if...else... structure to deal with different classes rather than using polymorphic. However, uncle bob said at the follow: > Consider what would happen if a perimeter() function were added to Geometry. The shape classes would be unaffected! Any other classes that depended upon the shapes would also be unaffected! On the other hand, if I add a new shape, I must change all the functions in Geometry to deal with it. Again, read that over. Notice that the two conditions are diametrically opposed.

So the concept of Data Structure and Object are come out: > Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.

Procedural code makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.

But again, as a OO programer, I can't take this, I want to deal with the scenario of change behavior more "elegantly".

Then Uncle bob jump out again and say: try Vistor pattern! (you can find it at the footnote in page 96)

Read more »
0%