HTTP/2

HTTP/1连接

在HTTP1中,每个请求和响应都占用一个TCP链接,尽管有Keep-Alive机制可以复用,但是在每个连接上同时只能有一个请求/响应,这意味着完成响应之前,这个连接不能用于其他请求。如果浏览器需要向同一个域名发送多个请求,需要在本地维护一个FIFO队列,完成一个再发送下一个。这样,从服务端完成请求开始回传,到收到下一个请求之间的这段时间,服务器处于空闲状态

后来,人们提出了HTTP管道的概念,试图把本地的FIFO队列挪到服务端。它的原理是这样的:浏览器一股脑把请求都发送给服务端,然后等着就可以了。这样服务端就可以在处理完一个请求后,马上处理下一个,不会有空闲了。甚至服务端还可以多线程并行处理多个请求。

HTTP/1优化

开源

既然一个TCP连接同时只能处理一个HTTP消息,那多开几条TCP连接不就解决这个问题了。

浏览器确实是这样做的。现代浏览器一般允许同域名并发6~8个连接。这个数字为什么不能更大呢?实际上这是出于公平性的考虑,每个连接对于服务器来说都会带来一定开销,如果浏览器不加以限制,一个性能好、带宽足的终端就可能耗尽服务器所有资源,造成其他人无法使用。

我们还会使用Cookie-Free Domain来减少静态文件带cookies的问题

节流

合并图片、js、css等

HTTP/2

开启Server Push。HTTP/2的多路复用特征,使得可以在一个连接上同时打开多个流,双向传输数据。Server Push,意味着服务端可以在发送页面HTML时主动推送其他资源,而不用等到浏览器解析到相应位置,发起请求再响应。另外,服务端主动推送的资源不是被内联在页面里,它们有自己独立的URL,可以被浏览器缓存。

Reference

https://imququ.com/post/http2-and-wpo-1.html

https://imququ.com/post/http2-and-wpo-2.html

HTTP2-high-perf-browser-networking.pdf

2016/4/16 posted in  网络

Web页面缓存

采用nginx+lua+redis进行页面缓存

1.配置nginx+lua+redis环境

安装lua解释器

wget http://luajit.org/download/LuaJIT-2.0.2.tar.gz

配置lua Libinclude/luajit-$version目录为环境变量

下载ngx_devel_kitlua-nginx-module

https://codeload.github.com/simpl/ngx_devel_kit/tar.gz/v0.2.19
https://codeload.github.com/openresty/lua-nginx-module/tar.gz/v0.9.10

安装配置nginx

http://nginx.org/download/nginx-1.4.7.tar.gz(http://nginx.org/en/download.html

nginx configue时候,将ngx_devel_kitlua-nginx-module两个编入到nginx

make 和make install

使用redis

lua解析json格式的数据 http://www.kyne.com.au/~mark/software/lua-cjson.php(默认安装就行)

lua封装redis调用接口,https://github.com/openresty/lua-resty-redis,安装,(并且redis.lua上层目录要有resty,因为require “resty.redis”,看代码,负责会出现找不到库)

lua_package_path "/opt/vendor/lua/?.lua;;";//指定redis.lua路径,;;指定默认路径  加在http段里
 
init_by_lua_file /usr/local/nginx/html/init.lua;

lua_code_cache off;//避免lua代码缓存,更改代码执行失效  

location /lua {  
      content_by_lua_file /usr/local/nginx/html/content.lua;  
} 加在加入一个location

拦截请求保存相应的页面缓存

location ~ /(index\.html|(goods|event)/[0-9]+\.html|video/list\.html|channel/class\.html)? {
    content_by_lua_file /app/nginx/conf/content.lua;
}     

加在加入一个location,拦截相应的请求,保存页面到redis缓存

缓存的更新与删除

新增定时项目,定时循环页面缓存redis的Key值,根据key值访问相应接口,返回的结果值MD5之后保存到redis的不用区。

添加定时任务定时扫描保存MD5缓存的key,分页面进行操作,比较接口返回结果的MD5值和redis缓存是否一致,不一致删除相应的redis页面缓存,对于商品的特别处理,商品下市删除相应的redisMD5缓存和redis页面缓存。

2016/4/15 posted in  others

Java中的Object对象

Java把现实中的任何事物都当做一个对象(Object),Java是面向对象的,就是Object-Oriented简称OO

Object在Java中被定义为一个顶级父类,它是任何类的父类,我们可以显示的继承它,也可以隐式继承

Object类中定义的常用方法

equals(Object obj)

equals()方法与==的区别:

==比较的是两个引用的值,即两个对象的地址。两次创建的对象是相互对立的,都各自分配了独立的内存空间,所有str1 != str2

equals()比较的是两个引用指向的对象的实际的值,涉及到对象的属性和方法。上例中两个对象的值都为Hello,所以str1.equals(str2)

由于Java中String类型是不可变的,也就是说在创建了一个字符串之后,如果想修改这个字符串的值是不能直接在原来的内存中修改存储的,而是需要重新分配一个内存空间用来存放新的内存空间

String类的这种特性造成在对String对象进行创建或操作时非常浪费内存空间,为了解决这个问题,Java中引出一个字符串池的概念(a pool of String)。即:如果当前准备新创建的字符串对象的值在复用池中已经存在,那么就不在生成新的对象,而是复用池中已有的字符串对象,新建的字符串和原来同值的字符串内存地址是相同的

注意的是,这种字符串池的机制只有采用Object obj ="Hello"方式(而非用new关键字)声明String对象的时候才有效。

hashCode()

Object类中定义了hashCode()方法决定了所有的对象都可以调用其hashCode()方法。

在HashMap的存储实现中,系统会根据对象的hashCode()值来决定每个元素的存储位置。

这个时候会有一个疑问,就是会不会出现两个对象的hashCode()值相同呢?

  • 对象相等则hashCode()一定相等;
  • hashCode()相等对象未必相等。

hashCode()存储机制中,不同的hashCode()值的对象会被分配到不同的“桶”里面,hashCode()值相同的对象会被放进同一个“桶”里面。在查询的过程中,一般是先遍历所有的桶再遍历桶里面的元素,所以为了能有一个高效的查询效果,我们应该尽可能的让所有的对象都被分配的自己独有的“桶”里面,这样才能最快的实现查询,要实现这样的要求就需要这些对象的hashCode()值不相同。

hashCode()equals()==三者的关系

  • 如果是基本变量,没有hashCode()equals()方法,基本变量的比较方式就只有==。因为他们不是对象,当然是可以通过Java中的包装类将他们转换成对象后还是可以调用hashCode()equals()()方法。
  • 如果是变量,由于在Java中所有变量定义都是一个指向实际存储的一个句柄(你可以理解为c++中的指针)
    • ==是比较句柄的地址(你可以理解为指针的存储地址),而不是句柄指向的实际内存中的内容
    • 如果要比较实际内存中的内容,那就要用equals()方法,
    • 但是如果是我们自己定义的一个类,比较自定义类用equals()==是一样的,都是比较句柄地址,因为自定义的类是继承于Object,而Object中的equals()就是用==来实现的,所以在自定义类的情况下重写equals()方法会是一个良好的习惯,否则失去了equals()方法存在的意义了
    • 那为什么我们用的String等等类型equals()是比较实际内容呢,是因为String等常用类已经重写了Object中的equals()方法,让equals()来比较实际内容
  • hashCode()在一般的应用中我们不需要了解hashCode()的用法,但当我们用到HashMaphashset等集合类时要注意下hashCode()。我们想通过一个Objectkey来拿HashMapvalueHashMap的工作方法是,通过你传入的ObjecthashCode()在内存中找地址,当找到这个地址后再通过equals()()方法来比较这个地址中的内容是否和你原来放进去的一样,一样就取出value
  • 所以这里要匹配2部分,hashCode()equals()。但假如说我们new一个Object作为key去拿value是永远得不到结果的,因为每次new一个Object,这个ObjecthashCode()是永远不同的,所以我们要重写hashCode(),你可以令你的hashCode()Object中的一个恒量,这样永远可以通过你的ObjecthashCode()来找到key的地址,然后你要重写你的equals()方法,使内存中的内容也相等

首先,从语法角度,也就是从强制性的角度来说,hashCode()equals()是两个独立的,互不隶属,互不依赖的方法,equals()成立与hashCode()相等这两个命题之间,谁也不是谁的充分条件或者必要条件。     

但是,从为了让我们的程序正常运行的角度,我们一定要(正确)重载hashCode(),使得equals()成立的时候,hashCode()相等,也就是

a.equals(b) -> a.hashCode()==  b.hashCode()

总结一下,equals()是对象相等性比较,hashCode()是计算对象的散列值,当然他们的依据是对象的属性。

对于equals(),一般我们认为两个对象同类型并且所有属性相等的时候才是相等的,在类中必须改写equals(),因为Object类中的equals()只是判断两个引用变量是否引用同一对象,如果不是引用同一对象,即使两个对象的内容完全相同,也会返回false。当然,在类中改写这个equals()时,你也可以只对部分属性进行比较,只要这些属性相同就认为对象是相等的。

对于hashCode(),只要是用在和哈希运算有关的地方,和equals()一样,在你的类中也应该改写。当然如果两个对象是完全相同的,那么他们的`hashCode()当然也是一样的,但是象前面所述,规则可以由你自己来定义,因此两者之间并没有什么必然的联系。     

当然,大多数情况下我们还是根据所有的属性来计算hashCode()和进行相等性比较。

Reference

http://blog.chinaunix.net/uid-26981819-id-4462638.html
http://www.cnblogs.com/I-am-Betty/archive/2010/09/06/1819375.html

2016/4/14 posted in  Java

深入Class文件结构

public class Message {
    public static void main(String[] args) {
        System.out.printf("junshan say:Hello Word!");
    }
}


Oolong的语法结构中以“.”符号开头表示这是一个基本的属性项,它对应到Java中就是表示一个Java的基本概念,如一个类、一个方法、一个属性、一个对象或者一个接口等。

类相关的指令

.source Message.java表示这个代码的源文件是Message.java

.class public Message表示这是一个类且公有的类名是Message

.super java/lang/Object表示这个类的父类是Object

方法的定义

.method public <init> ()V表示这是一个公有方法,没有参数,返回值类型是V(也就是void),<init>表示是构造函数

下面的.method public static main([Ljava/lang/String;)V表示的是main方法,它的参数是一个String类型的数组,其中[表示的是数组,而L表示的是一个类形式而不是基本数据类型,凡是L表示的类后面都会以;结尾,表示这个类的结束。

常量池

class文件中的常量池如下:



每个常量都是由三个字节来描述的。

第一个字节表示这个常量是什么类型的常量,JVM定义了12种类型的常量,每个种类的常量都会对应一个数值。

这些常量通常都是相互引用的,是一个常量引用了另一个常量。

UTF8常量类型

它可以存储多个字节长度的字符串值,如可以存储类名或者方法名等很长的一个字符串。

UTF8类型的常量由前两个字节来表示后面所存储的字符串的总字节数

01003c其中的3c表示后面所跟的字节长度有60个。

UTF8常量由三部分表示,包括这个常量是什么格式的,这个常量有多少个字节,后面就是这个常量实际的内容。

Fieldred、Methodref常量类型

为了描述Class中的属性项和方法。

0900100011 Fieldref类型常量

  • 前一个字节表示这个常量是Fieldref类型,所以是09
  • 后面两个字节表示的是该Fieldref是哪个类中的Field,存储的值是第几个常量的位置
  • 后面两个字节表示的是这个Fieldref常量的Name和Type,同样它也是指向NameAndType类型常量的索引

Class常量类型

Class常量表示的是该类的名称,它会指向另外一个UTF8类型的常量,该常量存储的是该类的具体名称

07表示的是Class类型的常量,后面的两个字节表示的是19个常量,而第19个常量正是一个UTF8类型的常量,该常量存储的是java/lang/Object,也就是该类的名称。

NameAndType常量类型

为了表示Methodref和Fieldref的名称和类型描述做进一步说明而存在的,名称通常又由UTF8常量类型来表示,而类型描述也由UTF8来表示,所以NameAndType类型是由一个字节的类型表示加上两个字节的UTF8的位置索引组成的。

  • 0007指向的是第7个常量,表示的是这个Methodref或者Fieldref的名称
  • 0008表示的是Methodref的返回类型或者Fieldref的参数类型

类信息

常量列表的后面就是关于这个类本身的信息描述了,如这个类的访问控制、名称和类型,以及是否有父类或者实现了某些接口等描述信息。

由两个字节表示这个类的访问控制描述

类访问控制的两个字节中实际上只使用了5个bit,其他的bit还没有定义,这5个bit中第一个bit表示的是该类是否是public的,为1的话就是public类,否则就是private类。所以对类的访问修饰只有两种,要么是public要么是private。

第5个bit表示的是该类是否是final类,1表示是,0表示否。

第6个bit描述该类是否含有invokespecial,也就是是否继承其他类,在Java中所有的类默认都继承了Object类。

第10个bit描述了该类是否是接口类,0表示不是接口类,1是接口类。

第12个bit表示该类是否是抽象类,0表示不是抽象类,1表示是抽象类。

后面两个字节0006是该类的类名称,它指向的是第6个常量,0004表示的是该父类的类名称,它指向的是第4个常量定义的名称,再后面的0000表示该类没有实现接口类。

2016/4/14 posted in  深入分析Java Web技术内幕

Thread Synchronization Utilities

We talk about synchronization when more than one concurrent task shares a resource.

The blocks of code that access this shared resource are called critical sections.

The high-level mechanisms are:

  • Semaphores: A semaphore is a counter that controls the access to one or more shared resources.
  • CountDownLatch: The CountDowLatch class is a mechanism provided by the Java language that allows a thread to wait for the finalization of multiple operations.
  • CyclicBarrier: The CyclicBarrier class is another mechanism provided by the Java language that allows the synchronization of multiple threads in a common point.
  • Phaser: The Phaser class is another mechanism provided by the Java language that controls the execution of concurrent tasks divided in phases. All the threads must finish one phase before they can continue with the next one.
  • Exchanger: The Exchanger class is another mechanism provided by the Java language that provides a point of data interchange between two threads.

Controlling concurrent access to a resource

A semaphore is a counter taht protects the access to one or more shared resources.

When a thread wants to access one of these shared resources, first, it must acquire that semaphore. If the internal counter of the semaphore is greater than 0, the semaphore decrements the counter and allows access to the shared resource. A counter bigger than 0 means there are free resources that can be used, so the thread can access and use one of them.

When the thread has finished the use of the shared resource, it must release the semaphore so that the other thread can access the shared resource. That operation increases the internal counter of the semaphore.

Binary semaphores protect the access to a unique shared resource, so the internal counter of the semaphore can only take the values of 1 or 0.

Fairness in semaphores

The default mode is called the non-fair mode. In this mode, when the synchronization resources is released, one of the waiting threads is selected to get this resource, but it's selected without any criteria. The fair mode changes this behavior and forces to select the thread that has been waiting for more time.

The Semaphore class admits a second parameter in its constructor. This parameter must take a Boolean value. If you give it the false value, you are creating a semaphore that will work in non-fair mode. You will get the same behavior if you don't use this parameter.

Controlling concurrent access to multiple copies of a resource

2016/4/13 posted in  Java7 Concurrency Cookbook