听到了一句话:
[code]
自由不是你想做什么就能做什么,而是你不想做什么就可以不做什么。
[/code]

觉得很有道理,查了一下出处,好像解释的不太对:
出自于德国哲学家康德的《道德形而上学原理》,判断一个行为是不是道德的要符合三个条件之一:自律性公式。
原意是:所谓自由,不是随心所欲,而是自我主宰。
把“自我主宰”解释成:“不想做什么就可以不做什么”,显然片面且极端,经不起推敲。

到底什么是自由呢?
[code]
在西方哲学里,叫:美。
在中国哲学里,叫:道。
在印度哲学里,叫:空(佛教)。
[/code]

先看代码
[code]
public E take() throws InterruptedException {
return takeFirst();
}

public E takeFirst() throws InterruptedException {
ReentrantLock localReentrantLock = this.lock;
localReentrantLock.lock();
try {
Object localObject1;
while ((localObject1 = unlinkFirst()) == null)
this.notEmpty.await();
Object localObject2 = localObject1;
return localObject2;
} finally {
localReentrantLock.unlock();
}
}
[/code]
问题1:当队列非空时,不会感知到被中断,也不会抛InterruptedException,除非队列空了。
有一种解释是当中断发生时,需处理完队列后才允许产生中断异常。按这种思路,生产者线程也要先检测中断,确保不会生产了,是否为空才有意义,实际上生产者并没有检验。
而带有超时时间的poll和offer操作,都会提前检查中断,用的是lockInterruptibly。
个人感觉:只要是会触发中断异常的地方,就应该用lockInterruptibly,不容易产生误解。

问题2:localObject2的存在是否有意义。
运行期经过复写传播(Copy Propagation)和无用代码消除(Dead Code Elimination)后,localObject2会直接消失,变成return localObject1;
作者这么干的意义是什么呢?感觉毫无意义。欢迎拍砖~

先贴代码,看运行结果:
[code]
Class<?> cache = Integer.class.getDeclaredClasses()[0];
Field c = cache.getDeclaredField("cache");
c.setAccessible(true);
Integer[] array = (Integer[]) c.get(cache);
array[130] = array[131];

Integer x = 2;
System.out.println(x + 2);
[/code]
运行结果实际上是5,其它地方如果出现Integer类型的数值,2就会变成3。

- 阅读剩余部分 -

业务中碰到单锚点同步多项数据问题,举个例子说明以备忘之。

概念解释:
锚点同步:client用自己得到的最后一次操作编号,来获取之后所有的操作,重放以达到状态一致。

问题描述:
多从库环境下,用一个锚点通过两次DAO去同步两类业务数据,有可能会因为两个从库的同步状态不一致,导致丢数据。
比如:用100锚点去同步时,先A业务,再B业务,同步A时,拉到123,同步B时拉到125,两次取数据间A业务产生了124操作。下次client用125来同步,会丢失124操作。

后续:
演练时发现跟是否双从或是否主从无关,只有主库的情况下同样有可能出现类似问题,两次操作有时差,没法保障数据一致(不可能锁上不让操作)。

解决办法:
每次同步时,记录每个业务的最大值操作编号max(a,b,c,d,...),下次以最大编号来拉时,每个业务按自己上次记录的编号拉。

问题:
有可能会出现用125来拉时,拉到124操作。相比之前的124操作丢失,会更好。
从单个业务看,一直是连续的不会丢,如果各业务间操作不耦合,不会有影响。
如果多业务间有时续要求,需要根据业务依赖关系来确定兼容方案,会更复杂,有两种方式可以解决:
1、拉完A后拉B,如果B小于A,则以A为准,可以结束;如果B大于A,拉B后再拉A(记做A1),丢弃掉A1中比B大的部分,以B为准。如果是多从库,必拉一次小的且拉小的数据的操作从主库进行。
2、耦合的业务操作,只重放到小编号的数据。这么做很安全,缺点是及时性差,而且如果某个业务较冷的时候,滞后会非常严重。
推荐方案1。

一直工作很好的线上服务,今天忽然发现有问题,原因是取到的本机IP是错的。
ifconfig的结果如下:
[code]
eth0 Link encap:Ethernet HWaddr 12:xx:xx:xx:xx:xx
inet addr:10.xx.xx.xx Bcast:10.xx.xx.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:347107351 errors:0 dropped:0 overruns:0 frame:0
TX packets:521084913 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:73368864377 (68.3 GiB) TX bytes:73126114339 (68.1 GiB)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:407951 errors:0 dropped:0 overruns:0 frame:0
TX packets:407951 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:112925033 (107.6 MiB) TX bytes:112925033 (107.6 MiB)
[/code]
取IP的时候过滤掉了非isSiteLocalAddress的IP:
[code]
public static String getLocalIp() {
Enumeration<NetworkInterface> ifs;
try {
ifs = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
return "";
}

while (ifs.hasMoreElements()) {
NetworkInterface i = ifs.nextElement();
Enumeration<InetAddress> as = i.getInetAddresses();
while (as.hasMoreElements()) {
InetAddress a = as.nextElement();
if (!a.isSiteLocalAddress()) continue;
return a.getHostAddress();
}
}
return "";
}
[/code]
取出来的是172.x.x.x,还能ping通,ping通后,arp信息中找不到对应的mac地址。瞬间晕了。

- 阅读剩余部分 -

单纯理解Java的初始化,可以认为有两步,静态初始化的类构造器clinit和实例化的实例构造器init的初始化。
clinit发生在首次访问期静态数据或方法时,再或者是首次new的时候,在init之前。

什么时候有clinit?
《深入理解Java虚拟机》书中给出了大致的答案:
[code]
<clinit>()方法是由编译器自动收集类中的所有变更的赋值动作和静态语句块(static{}块)中的语句产生的
[/code]
这句话总结的非常到位,但下面补的这一刀很容易把人带到沟里去,大意:
[code]
如果一个类中没有静态语句块,也没有对变量的赋值操作,可以不为这个类生成<clinit>()方法。
[/code]

直接的理解是,不出现下面这两种代码,就不需要clinit方法;相反的,出现了,就需要。
[code]
//1.静态变量或静态常量
private static Xxx xxx = ....;
private static final Yyy yyy = ...;

//2.静态代码块
static{
Xxx.xxx();
Yyy.yyy();
}
[/code]

实际上并不是这样的。我下面具体描述一下。

- 阅读剩余部分 -