为什么单例要写成这种鬼样子

用过Struts2的同学应该会觉得我写的单例很熟悉。。嗯就是Struts里面的View的写法。。。

所以单例为什么要这么写。或者说volatile和synchronized关键字有什么作用

代码在单线程模式下执行顺序会看起来和代码的位置相同。无论是什么编程语言都会有这样的错觉这归功于现代CPU做了一系列的优化和保证措施。但实际上代码片段在内存中会分成更细的几个部分;

例如a++这个操作机器指令就至少有三条,CPU不保证三条操作中不会插入其他的操作,所以,即使是你写的代码是单进程的,因为CPU有N多代码片段要执行,CPU不能保证每一步都能使原子操作;

JVM就当成一个逻辑上的PC,类似的CPU模型,也会导致同样的问题。

一个java程序中可能会有多个代码片段需要getInstance,如果进程A和进程B同时getInstance,就会有概率出现getInstance时候验空会两个进程都得到个空,然后同时new一个新的对象导致实例过程不正确。

物理机上的X86 CPU有CAS模块硬件实现原子性操作,而java在早期是通过锁来实现的。用锁来保证一段时间内只有一个进程能访问到getInstance代码片段,从而防止出现A,B都getInstance的时候都会new操作。

而volatile的做法是,同时也是volatile的含义是:

每当局部变量需要读取volatile修饰的字段时候,JVM总能保证是从不会将读取的指令插入到上一条将本地内存往主存写的过程之间。

一个正确的单例

public class A{
    public final static A instance = new A();
    public static A getA(){
        return instance;
    }
   //something to do
}
package com.liangyumingblog;

public class SimpleSinglton
{
    private static class Instance
    {
        private final static SimpleSinglton instance = new SimpleSinglton();
    }

    public SimpleSinglton getInstance()
    {
        return Instance.instance;
    }
}

 

Junit和Spring配合

JUnit官网

Spring官网

IDEA大杀器:JunitGenerator,可以自动生成Junit的测试接口,剩下我们就只要实现每个todo就好

为了配合Spring的注入,在测试的class前引入XML配置文件,和Spring-test套件

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("application.xml")

私有的方法用反射,public的方法实例化之后直接使用,记得每个java bean用工具生成好equals和hashcode。Junit就能和你的项目好好工作了

为什么我们要用getter/setter方法

第一,历史遗留原因,get/set方法从一种个人习惯被整个产业绑架了;

第二,面向对象的需要,我们可以把基本数据类型做输出前处理;

第三,我们可以把对数据的完整性的校验从流程类往基本对象身上推,逻辑层很少或者根本不用管理任何数据验证的事项,避免在逻辑代码中夹杂大量的数据校验(这个很重要,大部分业务代码为了尽快完成都是想到什么就是添加什么)。

 

代码重构

 

如下几个原则是必要的,也是今后落实代码时候要注意的:

  1. 数据类本身应该对自身的数据完整负责,加解密负责;
  2. 处理逻辑的对象尽量不要包含数据;
  3. 非数据验证的工具类抽取出来存放在单独的Utils类;
  4. 数据类的验证工具如果发现有复用,就要考虑对象是否有继承关系或者是共用一个接口,抽象出接口;
  5. 逻辑复杂的方法一定要降低复杂度,代码控制到20行以内一般就能够轻易地找出bug;
  6. 如果发现一个对象,经常是几部分数据互斥出现使用的,要考虑拆分成多个对象。

网络层级划分

OSI七层就不说了,在transportion描述的太详细了,其实可以归结为五层。

即是:

应用层(Application):Http,P2P这种,基本考虑的是字符串,内容。

运输层(Transportation):传输层用于确定应用层的消息用什么方式传输(可靠地传输或者是不可靠的传输,是否要流量限制等等)

网络层(Network):负责选择路径的层面(两个节点间会有大于等于一个的路由)

链路层(Data Link):协商每两个具体节点间的通信细节(直觉上认为是两个直达节点,没有第三个路由器之间的节点)