java 架构 模式    2016-02-28 13:08:30    1383    1    0

流水线

什么是流水线?

在计算机中,对于一条具体的指令执行过程,通常可以分为五个部分:取指令,指令译码,取操作数,运算 (ALU),写结果。
前三步由指令控制器完成,后两步则由运算器完成。
按照传统的方式,所有指令顺序执行,那么先是指令控制器工作,完成第一条指令的前三步,然后运算器工作,完成后两步,第一条指令执行完毕。然后第二条指令又是先指令控制器工作,完成前三步,然后运算器,完成第二条指令的后两部……
传统方式有个很大的缺点就是,指令只能一条一条地执行,仔细分析一下就会发现,这种方式存在很大的资源浪费:即同一时刻,要么指令控制器工作,运算器闲着;要么运算器工作,指令控制器闲着。这样一方面资源得不到有效利用,另一方面就是工作效率很低。
流水线的出现就是为了解决这个问题,下面我们来看一下流水线的工作模式:
假设有两个指令INS_A和INS_B,它们的执行分别要经过A,B,C,D四个过程,假设A到D四个过程分别由四个硬件元件完成。按照传统的方式,它们的流程如下:
传统方式
这种方式的缺点就是,只能一条指令一条指令的执行,并且当指令执行到过程B的时候,处理过程A和CD的元件是处于空闲状态的。

流水线方式如下:
流水线方式

说明一下,通过流水线的方式,当INS_A指令执行完过程A之后,处理过程A的元件就空闲了,此时我们就开始处理指令INS_B的A阶段,这样一来,INS_B指令只需要等到INS_A的A过程执行完成就可以继续执行了,这样以来就在很大程度上提高了效率。

流水线中断

使用流水线能够很大程度提高程序执行效率,这点是毋庸置疑的,但是,在系统中,每当引入一个新的模式或者组件的时候,我们就需要对应处理该模式或者组件所带来的问题,那么引入流水线的一个很大的问题就是流水线中断。

产生中断一般是由两个原因造成的,一个是“相关”,一个是“条件转移”。
相关:指的是一条指令的执行需要依赖前一条指令的执行结果。拿上面的例子,假设INS_B指令在执行过程C的时候,需要使用INS_A指令过程D的结果,那么指令INS_B在执行到C的时候,由于A指令的D过程还没有执行完成,所以此时INS_B就不能继续执行,否则就会拿到错误结果。所以此时就需要将流水线中断

服务器 nginx    2016-02-27 11:26:26    565    0    0

nginx 进程模型

一主多从

Nginx 在启动后,会有一个 master 进程和多个 worker 进程。master 进程主要用来管理 worker 进程,包含:接收来自外界的信号,向各 worker 进程发送信号,监控 worker 进程的运行状态,当 worker 进程退出后(异常情况下),会自动重新启动新的 worker 进程。而基本的网络事件,则是放在 worker 进程中来处理了。多个 worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个 worker 进程中处理,一个 worker 进程,不可能处理其它进程的请求。worker 进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。
nginx

IO模型

nginx采用异步非阻塞的方式来处理IO事件,具有很高的效率。

nginx如何处理请求?

如何解决并发问题?

  1. master进程创建socket,然后fork出多个子进程
  2. 当有请求到来的时候,所有的子进程都去竞争ngx_accept_disabled,只有成功获取到的进程才会创建连接。

支持的最大连接数?

在 Nginx 中,每个进程会有一个连接数的最大上限,这个上限与系统对 fd的限制不一样。在操作系统中,通过 ulimit -n,我们可以得到一个进程所能够打开的 fd 的最大数,即 nofile,因为每个 socket连接会占用掉一个fd,所以这也会限制我们进程的最大连接数,当然也会直接影响到我们程序所能支持的最大并发数,当 fd 用完后,再创建 socket 时,就会失败。

Nginx 通过设置worker_connectons 来设置每个进程支持的最大连接数。如果该值大于nofile,那么实际的最大连接数是 nofile,Nginx会有警告。

注意
worker_connectons设置的是每个进程的最大连接数,而不是nginx支持的最大连接数。
nginx支持的最大连接数应该是worker_connections * worker_processes,即每个进程的最大连接数与进程数的乘积。
而如果nginx被用作反向代理

java 异常    2016-02-23 20:03:57    1151    0    0

使用Dom4j解析xml文件的时候报错如下:

Exception in thread "main" java.lang.NoClassDefFoundError: org/jaxen/JaxenException
    at org.dom4j.DocumentFactory.createXPath(DocumentFactory.java:230)
    at org.dom4j.tree.AbstractNode.createXPath(AbstractNode.java:207)
    at org.dom4j.tree.AbstractNode.selectSingleNode(AbstractNode.java:183)
    at xml.XmlReader.main(XmlReader.java:29)
Caused by: java.lang.ClassNotFoundException: org.jaxen.JaxenException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 4 more

程序代码如下:

InputStream stream = XmlRead
杂谈    2016-02-21 20:35:01    205    0    0

学习的时候追根究底很重要,多问为什么,多思考可不可以不这样,多思考不同实现方式的不同点,多关注思路思想而不是具体实现。

经历过才懂得

如果说最初的notepad写代码是石器时代,那么现在的开发至少已经进入了工业时代,现在的开发人员有好用的写代码工具,好用的项目构建工具,好用的发布工具。极大的简化了之前的手动操作。这样的结果就是,很多初学编程者,上来就开始使用这些现成的工具,用得太理所当然,以至于离开了这些工具什么都干不了。
我想说的是,现在现成的工具能够很好的提高开发效率,我们应该去用,但是很多时候我们学习者也需要知道这些工具出现的原因,即为了解决什么问题而产生,同时也需要了解一下这些工具的原理。也就是说,现在技术发展的很快,很多新的工具或者很牛的框架出现,但是如果我们一开始就用这些工具或者框架,我们就无法体会到这些工具给我们带来的便利,因为我们不知道没有这些框架时候是什么样子。
比如Hadoop,Spark,Kafka等这些框架,如果我们在它们出现之前用过其他大数据处理框架或者分布式消息系统,那么我们遇到这些新的框架的时候我们才能很好的体会到这些新框架的特点,但是如果一到了某家公司就开始用这些,可能你都来不及考虑一下为什么要用这些而不是其他的。

所以我的结论之一就是:很多事情,你必须亲自经历过,才能体会到某种新技术或者框架出现的初衷,也能更清楚的明白这些框架之间的不同,区别,真正做到按需索取。

但现在存在的很大问题就是,很多初学者如果弄懂这些,需要学的东西很多很杂,如何定位如何取舍就决定了你的提高速度。所以在这方面,有一个大神带飞一下,真的很关键!

要走在技术的前沿

这条结论来自第一条,我们要想经历过才懂得,那么我们就必须在某项技术产生之时就跟进,只有这样才能一步步了解该技术的发展,才能对于技术的整体方向有个很好的把握。
但是这一条对于大多数人来讲真的是很难,你需要站在技术的最前端,在我的眼里都是些大神级别的,在开发过程中遇到过别人没有遇到过的问题和瓶颈,同时也致力于改变现状的人!
但是对于我们大部分开发人来说,保持这种意识也很关键,技术本来就是不断进步的,我们也需要能够及时了解技术发展动态,只有这样才能跟着技

spring 事务 BUG    2016-02-19 14:02:33    319    0    0

问题描述:

在Spring事务控制中,如果某个类的方法A和方法B都进行了事务控制(比如都加上了@Transactional注解),当在A方法中调用B方法的时候,实际运行过程中,B方法是不会被Spring事务控制的,而是仅仅对A方法进行了事务控制。

上述问题出现的典型代码如下:

public class SayHelloImpl implements SayHello {

    @Override
    @Transactional
    public void sayHi() {
        this.sayHello();
    }

    @Override
    @Transactional
    public void sayHello() {
        // do something..
    }

}

上面的方法,如果SayHello的sayHi方法被调用,sayHi方法在调用sayHello方法的时候,虽然sayHello方法也有Transactional控制,但实际上spring不会为该方法进行事务管理。
解决办法可参考:
http://www.iteye.com/topic/1122740

原理解释及模拟

由于Spring的事务控制本质上也是通过代理来实现,所以我们来看一下通过JDK动态代理实现会是什么样子:

假设有一个接口:

public interface SayHello {

    void sayHi();

    void sayHello();
}

接口实现类,注意sayHello方法里面调用了sayHi方法:

new SayHello() {

            @Override
            public void sayHi() {
                System.out.println("hi");
            }

            @Override
            public void sayHello() {
                this.sayHi(
linux    2016-02-14 13:58:41    186    0    0

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。

[xxxxx tmp]$ vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 980088 321688 4055932    0    0     0     1    0    0  1  0 99  0  0

默认命令给出的是从启动到现在的各项指标的平均值。也可以通过类似vmstat 1 2的命令来指定每隔一秒钟输出一次,一共输出两次。

[xxxxxx tmp]$ vmstat 1 2
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 977784 321688 4056248    0    0     0     1    0    0  1  0 99  0  0
 0  0      0 977908 321688 4056248    0    0     0     0  234  410  0  0 100  0  0

输出的gegelie

FIELD DESCRIPTION FOR VM MODE
   Procs
       r: The number of processes waiting for run time.
       b: The number of processes in uninterruptible sleep.

   Me
java 调优 JDK    2016-02-11 16:48:06    211    0    0

JPS命令

列出Java进程,常用命令jps -l可以显示当前系统中运行的java进程I等信息

查看当前系统中的java进程

jason@jason-Lenovo-V3000:~$ jps -l
6200 sun.tools.jps.Jps
5451 test.HttpServerTest
3055 /opt/eclipse//plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar

jstat命令

可以用来查看堆信息,垃圾回收信息等,详细使用命令可以通过man jstat命令来查看。

查看垃圾回收信息

jason@jason-Lenovo-V3000:~$ jstat -gc 5451
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
5120.0 5120.0  0.0    0.0   31744.0   1270.1   84992.0      0.0     4480.0 773.8  384.0   75.8       0    0.000   0      0.000    0.000
 S0C: Current survivor space 0 capacity (kB).

           S1C: Current survivor space 1 capacity (kB).

           S0U: Survivor space 0 utilization (kB).

           S1U: Survivor space 1 utilization (kB).

           EC: Current eden space capacity (kB).

           EU: Eden space utilization (kB).

           OC:
java 最佳实践    2016-02-11 15:45:19    297    0    0

很多东西会用兵不一定能用的好,虽然有时候自己灵光一闪,有一个好的想法,但是过去很久之后可能就会忘记,所以,还是把自己学到的一些技巧记录下来,总结一下

异常

适当扩大try-catch范围

例如下面的代码:

for (int i = 0; i < 10000; i++) {
            try {
                // do something..
            } catch (Exception e) {
                //handle exception
            }
        }

可以通过扩大异常捕获范围,即将try-catch拿到for循环外边来,可以在一定程度上提高性能。

变量

使用局部变量

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中,速度比较快。其他变量,如静态变量,实例变量等,都在堆中创建,速度相对较慢。

int a =0;
for (int i = 0; i < 10000; i++) {
            try {
                // do something..
            } catch (Exception e) {
                //handle exception
            }
        }

比下面代码要快

public static int ta =0;
    for (int i = 0; i < 1000000; i++) {
        ta++;
    }

位运算代替乘除法

通过位运算来代替乘除法,位运算仅仅通过左移或者右移就可以完成。
a*=2可以替换成a<<=1,a/=2可以替换成a>>=1

巧用数组替换判断及switch

例如下面的代码,用了很多switch判断:

public static void main(String[] args) {
        int ret=0;
        for (int i = 0; i < 1000000
java 基础    2016-02-10 10:26:37    602    0    0

long和double类型

在java中,long和double类型的数据都占8个字节长度,即64位。对于long和double类型的读写操作,java并不能保证其原子性。下面的内容来自Java Language Specification:

For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.
Writes and reads of volatile long and double values are always atomic.
Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
Some implementations may find it convenient to divide a single write action on a 64-bit long or double value into two write actions on adjacent 32-bit values. For efficiency’s sake, this behavior is implementation-specific; an implementation of the Java Virtual Machine is free to pe

java 基础    2016-02-06 19:06:38    3859    0    0

Thread.setContextClassLoader(ClassLoader cl)

在Java中提供了对于线程设置ContextClassLoader的方法,关于上下文类加载器,下面摘抄的内容将的比较明白:

线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()和 setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。
前面提到的类加载器的代理模式并不能解决 Java 应用开发中会遇到的类加载器的全部问题。Java 提供了很多服务提供者接口(Service Provider Interface,SPI),允许第三方为这些接口提供实现。常见的 SPI 有 JDBC、JCE、JNDI、JAXP 和 JBI 等。这些 SPI 的接口由 Java 核心库来提供,如 JAXP 的 SPI 接口定义包含在 javax.xml.parsers包中。这些 SPI 的实现代码很可能是作为 Java 应用所依赖的 jar 包被包含进来,可以通过类路径(CLASSPATH)来找到,如实现了 JAXP SPI 的 Apache Xerces所包含的 jar 包。SPI 接口中的代码经常需要加载具体的实现类。如 JAXP 中的 javax.xml.parsers.DocumentBuilderFactory类中的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例。这里的实例的真正的类是继承自 javax.xml.parsers.DocumentBuilderFactory,由 SPI 的实现所提供的。如在 Apache Xerces 中,实现的类是 org.apa