diff --git a/2015/09/11/Http-Servlet-Servlet-Contaniner/index.html b/2015/09/11/Http-Servlet-Servlet-Contaniner/index.html index c50586c..96bda1f 100644 --- a/2015/09/11/Http-Servlet-Servlet-Contaniner/index.html +++ b/2015/09/11/Http-Servlet-Servlet-Contaniner/index.html @@ -1,4 +1,4 @@ -Http,Servlet,Servlet Contaniner | 唐佳写字的地方

Http,Servlet,Servlet Contaniner

前记:刚学Java Web的时候,大部分人都是先接触的Servlet,然后用web.xml配置了几个小demon,知道了只要在前端中调用后台的方法与配置文件中一致,后台就能请求响应,并传达响应,然后又马上学SSH框架,写了各种xxx.action,xxx.do,对Servlet的原理已经越来越模糊。

+Http,Servlet,Servlet Contaniner | 唐佳写字的地方

Http,Servlet,Servlet Contaniner

前记:刚学Java Web的时候,大部分人都是先接触的Servlet,然后用web.xml配置了几个小demon,知道了只要在前端中调用后台的方法与配置文件中一致,后台就能请求响应,并传达响应,然后又马上学SSH框架,写了各种xxx.action,xxx.do,对Servlet的原理已经越来越模糊。

###1. Why should we use Servlet
For a B/S application,the most important thing is to response the different requests correctly ,but the requests from different clients are confused and disorderly so that the server is hard to analyse and response.So there is a protocol called HTTP(HyperText Transfer Protocol)to standard the request and response.

Back to Java Web, how does it recieve the requests from clients? So it comes the Servlet,Java itself doesn’t provide realization fot Servlet,it only define a standard for Servlet,or Interface,but you hava not to implement the interfaces,because there are some server software ,which have implemented the interfaces for you,like Tomcat,Jetty.

###2. How does it process requests
It’s strange and a little stupid to talk about how does a standard work,yes,it just define how to work.

@@ -10,4 +10,4 @@

Second,wo should write a General Servlet to recieve all the messages to the binding port,it must have two basic fuctions:anaylsing the whole message and fetch what you need,delivering the message that you fetch to the corresponding procedure.

Third,when the procedure recieve the right request,we start to process it and build the response,then we deliver it to the General Servlet.

Forth,the General Servlet recieves the reponse and decorates it to satisfy the HTTP,then deliver it to the fit place.

-
Aktie
第一篇
\ No newline at end of file +
Share
原码反码补码
\ No newline at end of file diff --git "a/2016/02/07/\345\216\237\347\240\201\345\217\215\347\240\201\350\241\245\347\240\201/index.html" "b/2016/02/07/\345\216\237\347\240\201\345\217\215\347\240\201\350\241\245\347\240\201/index.html" new file mode 100644 index 0000000..1744822 --- /dev/null +++ "b/2016/02/07/\345\216\237\347\240\201\345\217\215\347\240\201\350\241\245\347\240\201/index.html" @@ -0,0 +1,7 @@ +原码反码补码 | 唐佳写字的地方

原码反码补码

Q1. 为什么8位带符号的int 取值范围是[-128 ~ 127] ?

Q2. 为什么计算机表示带符号的数值要用补码?

1. 机器数和真值

机器数就是一个数在计算机中的二进制形式,最高位0代表正数,1代表负数。
真值就是这个机器数在计算机中所代表的值
例如:
1000 0001[机器数] = -1 [真值]

+
2. 原码

原码就是符号位加 真值 的绝对值。
1 [原码] = 0000 0001
-1 [ 原码] = 1000 0001

+
3. 反码

正数的反码就是它本身,负数的反码是符号位不变,其他位取反。
1[ 反码] = 0000 0001
-1 [反码] = 1111 1110

+
4. 补码

正数的补码同样是它本身 ,负数的补码是反码+1
1[补码] = 0000 0001
-1 [补码] = 1111 1111

+

A1:

现在可以回答Q1 了,因为计算机是用补码表示的数字,如果采用原码0000 0000 和 1000 0000 分别代表+0 和 -0 ,那么取值范围应该是 [-127~127],反码同理,+0的反码是 0000 0000 ,-0 的反码是 1111 1111,那么对于反码是1000 0000 的负数,原码是 1111 1111 即 -127,所以取值范围还是[ -127, 127 ], 对于补码而言,+0 的补码是0000 0000,-0的补码等于反码 1111 1111 加1 就溢出了,所以-127 的补码 的补码是 反码 1000 0000 加1 ,1000 0001,那么反码1000 0000 用来代表谁呢,就-128 吧。

+

A2:

为什么计算机要用补码来表示数值呢? 最大的原因我觉得是为了计算方便,CPU被设计的时候只定义了加法,一个bit只有1跟0 ,0+0=0,1+0=1,1+1=10。如果负数以补码的方式存储,则加减运算做起来十分方便。至于同余以后再研究。
所以 3+5= 0011 + 0101 = 1111 = 8
3 - 5 = 0011 + 1011 = 1110[补码] = 1101[反码] = 1010 [原码] = -2

+
Share
String为什么是不可变的
\ No newline at end of file diff --git "a/2016/03/07/String\344\270\272\344\273\200\344\271\210\346\230\257\344\270\215\345\217\257\345\217\230\347\232\204/index.html" "b/2016/03/07/String\344\270\272\344\273\200\344\271\210\346\230\257\344\270\215\345\217\257\345\217\230\347\232\204/index.html" new file mode 100644 index 0000000..9fed322 --- /dev/null +++ "b/2016/03/07/String\344\270\272\344\273\200\344\271\210\346\230\257\344\270\215\345\217\257\345\217\230\347\232\204/index.html" @@ -0,0 +1,16 @@ +String为什么是不可变的 | 唐佳写字的地方

String为什么是不可变的

1. 为什么String 是不可变的?

通过查看String的源代码发现,String的底层实现是通过一个 ==private final char[] value==; 也就是一个字符数组实现的,value 是一个引用,一旦指向堆中一个对象实例(数组也是一个对象)就不能再指向其他对象了,并且String并没有提供 setValue 方法,所以无法操作这个数组内存实例,所以String是不可变的。

+

2. 为什么String要设计成不可变的?

    +
  1. String interning 的设计
    1
    2
    String a = "abc";
    String b = "abc";
    +
  2. +
+

如果“abc”对象实例第一次被引用指向,则在堆中一个String常量缓存池中加入”abc”,b 也指向该缓存池中的”abc”,如果String 是可变的,那么其中一个引用改变它的值将会对其他引用变量造成影响。

+
    +
  1. 安全问题
    很多连接配置就是用的String,如果中途可以被改变的话或造成安全问题。

    +
  2. +
  3. 因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。

    +
  4. +
  5. 类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。
  6. +
  7. 因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。
  8. +
+

3. 怎么改变String的值?

String的成员属性 private final char[] value 毕竟只是一个引用变量,它不可以指向其他对象实例,但是我们可以改变它当前指向的对象实例的值,通过反射。

+
Share
JVM内存模型
\ No newline at end of file diff --git "a/2016/04/20/\347\254\254\344\270\200\347\257\207/index.html" "b/2016/04/20/\347\254\254\344\270\200\347\257\207/index.html" index 29f1ac2..821a983 100644 --- "a/2016/04/20/\347\254\254\344\270\200\347\257\207/index.html" +++ "b/2016/04/20/\347\254\254\344\270\200\347\257\207/index.html" @@ -1,4 +1,4 @@ -第一篇 | 唐佳写字的地方

第一篇

asdasd

+第一篇 | 唐佳写字的地方 \ No newline at end of file +
Partager
哈哈
\ No newline at end of file diff --git "a/2016/05/11/JVM\345\206\205\345\255\230\346\250\241\345\236\213/index.html" "b/2016/05/11/JVM\345\206\205\345\255\230\346\250\241\345\236\213/index.html" new file mode 100644 index 0000000..f995fbf --- /dev/null +++ "b/2016/05/11/JVM\345\206\205\345\255\230\346\250\241\345\236\213/index.html" @@ -0,0 +1,23 @@ +JVM内存模型 | 唐佳写字的地方

JVM内存模型

JVM内存图

+

JVM在运行时内存模型:

线程私有内存区:

程序计数器(Program Counter Programming)

程序计数器可以看做是当前线程所执行的字节码的行号指示器,字节码解析器就是通过改变这个计数器的值来选取下一条要执行的代码,像分支,循环,跳转,线程恢复都需要依赖它只能知道下一条执行语句的位置。所以他是每个线程私有的。
当执行的是java方法的时候,它记录的是当前正在运行的虚拟机字节码指令的地址。当执行native方法的时候,值为Undefine,此内存区是唯一没有异常的区域。

+
虚拟机栈( VM Stack )

VM Stack
虚拟机栈描述的 Java 方法执行的内存模型,每执行一个方法就会向 stack 压入一个栈帧(Stack Frame),里面包含了局部变量表,操作数栈,动态链接,方法出口,从方法调用到执行,对应着一个栈帧的入栈到出栈,所以他也是线程私有。

+

局部变量表,也就是常说的堆和栈里面的“栈”,它包含基本数据类型,对象的引用类型( reference ),returnAddress(指向一条字节码指令的地址)

+

栈的深度决定了方法调用的深度,可以用 -Xss 修改,请求栈深度大于虚拟机允许的深度,会抛出 StackOverFlowError 异常,如果虚拟机栈是动态扩展,那么扩展的时候会申请内存,不够会抛出 OutOfMemoryError

+
本地方法栈 (Native Method Stack)

和虚拟机栈类似,只不过是针对 native 方法,有的虚拟机把两个合二为一了(Sun Hotspot)。

+

线程共享内存区

Java堆(Java Heap)

存放对象实例的地方,但并不绝对( 针对栈上分配,标量替换等优化技术)。是GC的主要区域,物理上可以使连续内存区,也可以不连续,逻辑上连续即可。通过 -Xmx -Xms 控制内存大小,内存不够时会抛出 OutOfMemoryError

+
方法区(Method Area)

存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。GC行为在此区域较少,主要是常量池回收和类型卸载。

+

直接内存(Direct Memory)

不属于JVM的运行时内存,可以用NIO中的DirectByteBuffer操作。

+

####附 JVM常用参数

+
    +
  • -XX:+PrintGCDetails 打印垃圾回收信息
  • +
  • -Xms 为Heap区域的初始值,线上环境需要与-Xmx设置为一致,否则capacity的值会来回飘动
  • +
  • -Xmx 为Heap区域的最大值
  • +
  • -Xss(或-ss) 线程栈大小(指一个线程的native空间)1.5以后是1M的默认大小
  • +
  • -XX:PermSize与-XX:MaxPermSize 方法区(永久代)的初始大小和最大值(但不是本地方法区)
  • +
  • -XX:NewRatio 老年代与新生代比率
  • +
  • -XX:SurvivorRatio Eden与Survivor的占用比例。例如8表示,一个survivor区占用 1/8 的Eden内存,即1/10的新生代内存,为什么不是1/9?因为我们的新生代有2个survivor,即S1和S22。所以survivor总共是占用新生代内存的 2/10,Eden与新生代的占比则为 8/10。
  • +
  • -XX:MaxHeapFreeRatio GC后,如果发现空闲堆内存占到整个预估的比例小于这个值,则减小堆空间。
  • +
  • -XX:MinHeapFreeRatio GC后,如果发现空闲堆内存占到整个预估的比例大于这个值,则增大堆空间。
  • +
  • -XX:NewSize 新生代大小
  • +
+
Share
关于GC
\ No newline at end of file diff --git "a/2016/06/09/\345\205\263\344\272\216GC/index.html" "b/2016/06/09/\345\205\263\344\272\216GC/index.html" new file mode 100644 index 0000000..a7d0f0e --- /dev/null +++ "b/2016/06/09/\345\205\263\344\272\216GC/index.html" @@ -0,0 +1,52 @@ +关于GC | 唐佳写字的地方

关于GC

先来看三个问题:

+
    +
  • 那些对象需要被回收
  • +
  • 什么时候回收
  • +
  • 怎么回收(回收的策略)
  • +
+

哪些对象需要被回收?

引用计数法

被有新的引用计数加1,引用被销毁引用减1,但是无法解决循环引用的问题。

+
1
2
3
4
5
6
Object a = new Object();
Object b = new Object();
a = b;
b = a;
a = null;
b = null;
+

执行到第五行的时候a,b引用计数均为2,然后a,b=null,引用计算减一,如果a要被清除,不需要满足引用计算为0,就是说他的一个引用b必须要被清除,但是b又引用a,要等待a被清除。所以陷入死循环。

+

可达性分析算法

把一些列 "GC ROOT"节点作为起始点开始搜索,走过的路径称为引用链(Reference Chain),当一个对象不在引用链上,那么就可以被回收了。这里有两点需要注意,什么可以作为GC ROOT,以及什么是引用.

+

GC ROOT:

+
    +
  1. static属性引用的对象
  2. +
  3. final常量引用的对象
  4. +
  5. 当前栈帧的本地变量区
  6. +
  7. native方法引用的对象
  8. +
+

引用:

+
    +
  1. 强引用,永远不会回收。
  2. +
  3. 软引用
  4. +
+
1
2
Object obj = new Obj;
SoftReference<Object> sof = new SoftReference<Object>(obj);
+

只有当内存不够的时候才回收。

+
    +
  1. 弱引用
  2. +
+
1
2
Object obj = new Obj;
WeakReference<Object> wf = new WeakReference<Object>(obj);
+

下一次垃圾回收的时候回收。

+
    +
  1. 虚引用(幽灵引用)
  2. +
+
1
2
Object obj = new Object();
PhantomRefrence<Object> pf = new PhantomRefrence<Object>(obj);
+

垃圾回收的时候就回收。

+

什么时候回收

对象优先在堆区新生代的eden分区分配,当eden分区内存不够,此时触发 Minor GC,多次存活的对象将放入老年代,老年代内存不够的话会触发Full GC,你也可以手动调用System.gc()进行回收,但这只是告诉GC线程进行垃圾回收,具体时候执行和什么时候执行还不一定(类似启动一个线程)。

+

怎么回收

怎么回收就要谈一下垃圾回收的常用算法了。

+

标记清除算法(Mark-Sweep)

标记处所有要清除的对象,然后在回收所有被标记的。
实现简单,缺点也很明显:

+
    +
  1. 效率低
  2. +
  3. 造成内存不连续,分配大对象的时候会造成GC
  4. +
+

这是最基础的垃圾回收算法。

+

复制算法(Copying)

把内存分为相等的两块,每次使用其中一块,GC时先把存活的对象复制到另一块上,在对整块清除。高效,但是浪费了一半的内存空间。但是通常不会等分,而是按8:1:1分配。

+

标记整理算法( Mark-compact)

在标记清除的基础上,对存活的对象从内存的最左端重新排序整理,使空闲的地址空间连续。缺点是效率低。

+

分代收集(Generational Collection)

这个算法没什么新的特性,主要是把堆Heap上的空间分为新生代(Young Generation) 和 老年代(Tenured Generation)。

+

所以现代商用虚拟机大部分是用这种算法清理新生代,但不是五五分,而是把它分为1 8 1,只浪费百分之十内存。

+

把新生代分为2个survivor(各占10%),一个Eden(80%),内存分配在一个survivor和Eden分区,当清理的时候,把存活的对象(一般不超过10%)复制顺序到另一个survivor分区上,然后清理当前的survivor和eden分区。下次分配内存的时候在eden和被复制的survivore分区上分配。

+

当survivor空间不够时,会向(Tenured Generation)申请内存空间。当survivor分区的对象对此未被回收(年龄计数器加一),说明这个对象可能长时间都不会被回收,那么每次在对其进行GC ROOT扫描是浪费的,所以会把它移动到老年代。

+

老年代(Tenured)的对象都是些持久不易被回收的对象,所采的回收算法一般是标记清除或标记整理。

+

新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具
备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。

+

老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常
会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里
就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10
倍以上。

+
Share
线程 进程 并发 并行
\ No newline at end of file diff --git a/2016/07/20/Contaniner/index.html b/2016/07/20/Contaniner/index.html index 2e5fe6d..c8b68c1 100644 --- a/2016/07/20/Contaniner/index.html +++ b/2016/07/20/Contaniner/index.html @@ -1 +1 @@ -Contaniner | 唐佳写字的地方

Contaniner

Aktie
\ No newline at end of file +Contaniner | 唐佳写字的地方
\ No newline at end of file diff --git a/2016/07/20/hello-world/index.html b/2016/07/20/hello-world/index.html index f1841d2..b1798af 100644 --- a/2016/07/20/hello-world/index.html +++ b/2016/07/20/hello-world/index.html @@ -1,4 +1,4 @@ -Hello World | 唐佳写字的地方

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

+Hello World | 唐佳写字的地方

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server
@@ -7,4 +7,4 @@

Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

-
Aktie
Contaniner
\ No newline at end of file +
Partager
Contaniner
\ No newline at end of file diff --git "a/2016/07/20/\345\223\210\345\223\210/index.html" "b/2016/07/20/\345\223\210\345\223\210/index.html" index bf03c7b..0248207 100644 --- "a/2016/07/20/\345\223\210\345\223\210/index.html" +++ "b/2016/07/20/\345\223\210\345\223\210/index.html" @@ -1 +1 @@ -哈哈 | 唐佳写字的地方

哈哈

Aktie
Hello World
\ No newline at end of file +哈哈 | 唐佳写字的地方

哈哈

Partager
Hello World
\ No newline at end of file diff --git "a/2016/07/27/\347\272\277\347\250\213-\350\277\233\347\250\213-\345\271\266\345\217\221-\345\271\266\350\241\214/index.html" "b/2016/07/27/\347\272\277\347\250\213-\350\277\233\347\250\213-\345\271\266\345\217\221-\345\271\266\350\241\214/index.html" new file mode 100644 index 0000000..16f48d4 --- /dev/null +++ "b/2016/07/27/\347\272\277\347\250\213-\350\277\233\347\250\213-\345\271\266\345\217\221-\345\271\266\350\241\214/index.html" @@ -0,0 +1,19 @@ +线程 进程 并发 并行 | 唐佳写字的地方

线程 进程 并发 并行

任务调度

线程是什么?要理解这个概念,须要先了解一下操作系统的一些相关概念。大部分操作系统(如Windows、Linux)的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每个任务轮流执行。任务执行的一小段时间叫做时间片,任务正在执行时的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态等待下一个属于它的时间片的到来。这样每个任务都能得到执行,由于CPU的执行效率非常高,时间片非常短,在各个任务之间快速地切换,给人的感觉就是多个任务在“同时进行”,这也就是我们所说的并发(别觉得并发有多高深,它的实现很复杂,但它的概念很简单,就是一句话:多个任务同时执行)

+
关于多线程提升效率:
    +
  1. 在单核cpu下,程序存在大量等待的耗时操作,比如从网络接受数据,从硬盘读取大文件,也就是所谓的阻塞,此时cpu处于闲置状态,此时多线程能提升效率,宏观上程序是并行的,但是微观上仍旧不是并行的。
  2. +
  3. 在多核cpu下,程序能够做到真正的并行,此时能提高效率。
  4. +
+
关于线程,进程的区别:
    +
  1. 进程,其实是操作系统对一个正在运行的程序的抽象,操作系统会给它分配独立的资源,而且每个进程之间的资源相对独立,在操作系统级别上,它是资源调度和分配的独立单位,而线程,可以看作是进程中执行的一段代码流,多个线程共享一个进程内的内存资源(除了必要的栈和程序计数器独立),线程是cpu执行的最小单位。
  2. +
  3. 进程之间不共享内存,而且在操作系统层面上相对独立,所以进程之间的通信开销是很大的,而线程共享内存,通信比较方便。
  4. +
  5. 进程一般由程序、数据集合和进程控制块三部分组成。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集合是程序在执行时所需要的数据和工作区;程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的唯一标志。
  6. +
  7. 线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成
  8. +
+
进程与线程的区别

前面讲了进程与线程,但可能你还觉得迷糊,感觉他们很类似。的确,进程与线程有着千丝万缕的关系,下面就让我们一起来理一理:

+
    +
  1. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
  2. +
  3. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
  4. +
  5. 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见;
  6. +
  7. 调度和切换:线程上下文切换比进程上下文切换要快得多
  8. +
+
Share
也谈谈字符
\ No newline at end of file diff --git "a/2016/07/29/java\344\270\255\347\232\204\345\244\232\347\272\277\347\250\213/index.html" "b/2016/07/29/java\344\270\255\347\232\204\345\244\232\347\272\277\347\250\213/index.html" new file mode 100644 index 0000000..2e3ea9a --- /dev/null +++ "b/2016/07/29/java\344\270\255\347\232\204\345\244\232\347\272\277\347\250\213/index.html" @@ -0,0 +1,2 @@ +Java中的多线程 | 唐佳写字的地方

Java中的多线程

任何程序都有一个线程,java程序已启动就已经启动了两个线程,一个是main线程,一个是gc线程,用来回收。

+
Partager
也谈谈字符
\ No newline at end of file diff --git "a/2016/08/07/\344\271\237\350\260\210\350\260\210\345\255\227\347\254\246/index.html" "b/2016/08/07/\344\271\237\350\260\210\350\260\210\345\255\227\347\254\246/index.html" new file mode 100644 index 0000000..de8cec0 --- /dev/null +++ "b/2016/08/07/\344\271\237\350\260\210\350\260\210\345\255\227\347\254\246/index.html" @@ -0,0 +1,18 @@ +也谈谈字符 | 唐佳写字的地方

也谈谈字符

1.计算机只认识字节

计算机其实只存储和处理字节bit,对它而言,根本没有字符这个概念,字符是给人理解的,也就是说,字符都是在内存中才形成的,在硬盘上只有字节。

+
    +
  • 字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
  • +
+

2.怎么转换:字符编码

当计算机把字节和字符转换的时候,势必要有一种规则,这就是字符编码,比如说A,在ASCII编码中对应的数字是65,所以计算机存储的二进制是(0100_0001)。

+

3.每个国家有不同的字符集合:字符集

其实字符编码就是字符到字节的映射规则,但是如果每个国家都有自己的规则就乱了,所以就有了字符集:制定了字符的集合,规定了某个字符对应什么数字(字节)。

+

所以换个角度看,字符集是规定,字符编码是实现。

+

4. ASCII

ASCII编码规定了一些符号,字母和数字的编码,一共128个,当我们提及ASCII,既表示了一种字符集,也代表了一种字符编码。

+

5. ISO-8859-1(又称Latin-1)

ASCII 编码是美国人制定的,并没有考西欧的一些字母,考虑到一个字节有2的八次方256位,而ASCII只用了低4位,还有高四位没用,于是欧洲采用了ISO-8859-1 编码,该编码在ASCII的基础上,增加了128高四位。

+

6. GBK和GB2312

ISO-8859-1已经1byte可用的位全用完了,其他语言怎么办,于是,中国人决定2个byte来表示他们包含汉字的字符集 GB2312, GB2312zh7000多个字符,对于博大精深的汉字还是不够,于是它的超集 GBK 被制定了。

+

7. Unicode字符集 UTF编码

Unicode字符集指在统一不同国家的字符集。Unicode是一个符号集,它只规定了符号和和对应的二进制编码,他并没有规定二进制编码怎么传输和存储。比如说Unicode字符对应的数字1,你可以用1个字节,也可以用两个字节存储。而这些,是UTF(UCS Transformation Format)做的。

+

UTF: Unicode字符集的编码标准。

+
    +
  • UTF-16: 固定用两个字节表示一个字符
  • +
  • UTF-32: 固定用四个字节表示一个字符
  • +
  • UTF-8:变长字节,用1-4个字节表示一个字符,是互联网传输编码用的最广泛的,隐含了赫夫曼编码思想,用最短的编码表示使用最频繁。
  • +
+
Share
笔记:关于TCP协议和IO的基础
\ No newline at end of file diff --git "a/2016/08/10/\347\254\224\350\256\260-\345\205\263\344\272\216TCP\345\215\217\350\256\256\345\222\214IO\347\232\204\345\237\272\347\241\200/index.html" "b/2016/08/10/\347\254\224\350\256\260-\345\205\263\344\272\216TCP\345\215\217\350\256\256\345\222\214IO\347\232\204\345\237\272\347\241\200/index.html" new file mode 100644 index 0000000..de41b1c --- /dev/null +++ "b/2016/08/10/\347\254\224\350\256\260-\345\205\263\344\272\216TCP\345\215\217\350\256\256\345\222\214IO\347\232\204\345\237\272\347\241\200/index.html" @@ -0,0 +1,25 @@ +笔记:关于TCP协议和IO的基础 | 唐佳写字的地方

笔记:关于TCP协议和IO的基础

java nio这块看了很多次,但是每次都是粗浅的看了下大概,导致很多东西回头又忘了,再加上现在nio这块现在容器封装的太深,你在平时根本就没有接触的机会。所以,要能记住不常用的东西,最简单办法就是从底层上理解他。

+

1. TCP协议为什么比UDP可靠

    +
  • 首先,TCP协议在传输数据前需要跟服务器进行握手,确保了服务器可以正常访问和回复。
  • +
  • 其次,TCP每次传输数据都要求对端确认,如果没有确认会重传。
  • +
  • TCP会对传输的数据分块并排序,每一块都要一个序列号,对端收到的时候会把块按序号重新排列,重复的删去,这保证了数据的完整性和有序性。
  • +
  • TCP是面向连接的,面向连接指的是在传输数据前,双端应该先通过三次握手建立连接。
  • +
+

2. TCP连接三次握手

TCP连接三次握手

+
    +
  • 客户端发送SYN分节,告诉服务端初始序列号:j,通常不包含其他数据,所在IP数据报中只有IP首部和TCP首部。
  • +
  • 服务器针对j,回应 ACK:j+1,同时向客户端发送SYN k,以确保客户端也能正常回应。
  • +
  • 客户端回应ACK k+1。
  • +
+

3. 为什么TCP三次握手而不是两次

我能想到一个场景,客户端向服务器发送第一次SYN后,假如说网络延时,SYN一直没到服务器,客户端就closed了,后面服务器接到SYN回应ACK,两次握手已经完了,这个时候客户端的状态对服务器是不可知的,服务器没法判断建立成功了没。

+

4. TCP关闭四次挥手

TCP四次挥手

+
    +
  • A端发送FIN n,表示我已经没有数据可以传给你了,请求关闭这个连接。
  • +
  • B端收到FIN n,回复ACK n+1,表示我已经收到这个请求,然后给应用层传递一个文件结束符,放入B端待读数据队列的末尾,告诉应用层A端已经没有数据可以传输了
  • +
  • B端应用读到文件结束符后调用close套接字,并向A发送FIN m。
  • +
  • A端回复ACK m+1。
  • +
+

5. 为什么关闭要四次握手

关闭不一定是四次握手,因为连接和关闭的机制原理其实是一样的,都是双端一应一答,只不过连接的时候把B端的应答放在一起了,而关闭理论上不放在一起是因为当A端告诉B端要关闭连接的时候,B端可能还有一些东西还要处理,比如说还有可能要发送一些数据给A端,所以只能先回复A的FIN,告诉它我收到连接了,等处理完了再发送FIN给A端。

+

6. 端口到底是什么

我指的是网络传输中虚拟的端口,显然只有在需要传输交互的时候才有端口的概念,所以端口可以看做是计算机给进程维护的一个与外部通信的标识号,比如说A程序要给另一台服务器的B进程发信息,找到服务器后,必须要通过一个标识才能知道要发给哪个进程。数据而端口正式这个标识。系统在为每个端口维护了一个队列,新来的数据只要放到对应队列里就可以了。

+

为什么计算的端口通常最大是65535,因为在传输层的协议中Header Format最前端是Source Port和Destination Port,每个都是2个字节。所以说这是协议规定的,并不是什么物力资源限制。

+
Share
好无聊啊~写写排序算法?
\ No newline at end of file diff --git "a/2017/01/12/\345\245\275\346\227\240\350\201\212\345\225\212-\345\206\231\345\206\231\346\216\222\345\272\217\347\256\227\346\263\225\357\274\237/index.html" "b/2017/01/12/\345\245\275\346\227\240\350\201\212\345\225\212-\345\206\231\345\206\231\346\216\222\345\272\217\347\256\227\346\263\225\357\274\237/index.html" new file mode 100644 index 0000000..ed55476 --- /dev/null +++ "b/2017/01/12/\345\245\275\346\227\240\350\201\212\345\225\212-\345\206\231\345\206\231\346\216\222\345\272\217\347\256\227\346\263\225\357\274\237/index.html" @@ -0,0 +1,2 @@ +好无聊啊~写写排序算法? | 唐佳写字的地方

好无聊啊~写写排序算法?

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
public class ArraySort {
/**
* 直接插入排序 最坏复杂度 n2
* 每一次都插入到一个已排序的序列中 稳定的排序
* @param array
* @return
*/
public static int[] straightInsertionSort(int[] array){
if (array == null){
return array;
}
for (int i = 1;i < array.length; i++) {
for (int j = 0; j < i; j++) {
if (array[i]<array[j]){
int t = array[i];
for (int k = i; k > j; k--) {
array[k] = array[k-1];
}
array[j] = t;
continue;
}
}
}
return array;
}
/**
* 希尔排序 插入排序的一种
* @param array
* @return
*/
public static int[] shellSort(int[] array){
// 增量gap
for (int gap = array.length/2; gap > 1 ; gap/=2) {
// 直接插入排序
for (int i = 0; i < gap; i++) {
for (int j = i+gap; j < array.length; j += gap) {
if (array[j] < array[i]){
// 插入 后面的向后移动
int t = array[j];
// for ()
}
}
}
}
return array;
}
/**
* 平均n*lgn 最坏n2
* @param array
* @return
*/
public static int[] quickSort(int[] array){
quickSort1(array,0,array.length-1);
return array;
}
public static void quickSort1(int[] array,int left,int right){
if (left>=right){
return;
}
int baseValue = array[left];
int baseIndex = left;
while (left<right){
while (array[right] >= baseValue && left < right)
right--;
while (array[left] <= baseValue && left < right)
left++;
swap(array,left,right);
}
// swap(array,baseIndex,left);
array[baseIndex] = array[left];
array[left] = baseValue;
quickSort1(array,baseIndex,left);
quickSort1(array,left+1,right);
}
// public static void quickSort1(int[] array,int start,int end){
// System.out.println(start+" "+end);
// if (start == end){
// return ;
// }
// int i = start + 1;
// int j = end;
// int baseValue = array[start];
// while (i<j){
// while (array[j]>=baseValue){
// j--;
// }
//
// while (array[i]<baseValue && i<j){
// i++;
// }
//
// System.out.println(i+" "+j);
// swap(array,i,j);
// }
// swap(array,start,i);
// quickSort1(array,start,i);
// quickSort1(array,i+1,end);
// }
/**
* 冒泡 n2
* @param array
* @return
*/
public static int[] bubbleSort(int[] array){
if (array == null){
return array;
}
for (int i = 0; i < array.length-1; i++) {
for (int j = array.length-1; j > i; j--) {
if (array[j]<array[j-1]){
swap(array,i,j);
}
}
}
return array;
}
/**
* 选择排序 n2 每次选择最小的 也算冒泡的一种 但是减少了交换次数,只有n-1次交换。
* @param array
* @return
*/
public static int[] selectSort(int[] array){
if (array == null){
return array;
}
for (int i = 0; i < array.length -1; i++) {
int minIndex = i;
for (int j = i+1; j < array.length; j++) {
if (array[minIndex] > array[j]){
minIndex = j;
}
}
if (minIndex != i){
swap(array,i,minIndex);
}
}
return array;
}
/**
* 计数排序 n 但是对数字有要求
* @param array
* @return
*/
public static int[] countSort(int[] array){
int maxIndex = 0;
for (int i = 1; i < array.length; i++) {
if (array[maxIndex] < array[i]){
maxIndex = i;
}
}
int[] array1 = new int[array[maxIndex]+1];
for (int i = 0; i < array.length; i++) {
array1[array[i]]+=1;
}
int[] newArray = array;
int index = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i]; j++) {
newArray[index++] = i;
}
}
return newArray;
}
/**
* 归并排序
* @param array
*/
public static int[] mergeSort(int[] array){
// divice(array,0,array.length-1);
mergeSort1(array,0,array.length-1);
return array;
}
public static void mergeSort1(int[] array,int left,int right){
int mid = (left+right)/2;
if (left<right){
mergeSort1(array,left,mid);
mergeSort1(array,mid+1,right);
mergeArray(array,left,right);
}
}
public static void mergeArray(int[]array,int left,int right){
int[] tmp = new int[right-left+1];
int mid = (left+right)/2;
int index = 0;
int i = left;
int j = mid+1;
while (i<=mid && j<=right){
if (array[i] < array[j]){
tmp[index++] = array[i++];
}else {
tmp[index++] = array[j++];
}
}
// 把左边的放入tmp
while (i<=mid){
tmp[index++] = array[i++];
}
while (j<=right){
tmp[index++] = array[j++];
}
for (int k = 0; k < tmp.length; k++) {
array[left++] = tmp[k];
}
}
// public static void merge(int[] array,int left,)
static void swap(int[] array,int i,int j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void printArray(int[] t){
if (t == null){
System.out.println(t);
return;
}
for (int i = 0; i < t.length; i++) {
System.out.print(t[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] array = RandomUtil.randomIntArray(100,10);
printArray(array);
// int[] array1 = {43, 74, 72, 9, 10, 43 , 93 , 15 ,36 ,0 };
// bubbleSort(array);
// printArray(countSort(array));
printArray(mergeSort(array));
printArray(array);
// printArray(straightInsertionSort(array));
// printArray(array);
}
}
+
Share
用wait和notify实现简单的生产-消费模式
\ No newline at end of file diff --git "a/2017/01/20/\347\224\250wait\345\222\214notify\345\256\236\347\216\260\347\256\200\345\215\225\347\232\204\347\224\237\344\272\247-\346\266\210\350\264\271\346\250\241\345\274\217/index.html" "b/2017/01/20/\347\224\250wait\345\222\214notify\345\256\236\347\216\260\347\256\200\345\215\225\347\232\204\347\224\237\344\272\247-\346\266\210\350\264\271\346\250\241\345\274\217/index.html" new file mode 100644 index 0000000..8531b6d --- /dev/null +++ "b/2017/01/20/\347\224\250wait\345\222\214notify\345\256\236\347\216\260\347\256\200\345\215\225\347\232\204\347\224\237\344\272\247-\346\266\210\350\264\271\346\250\241\345\274\217/index.html" @@ -0,0 +1,3 @@ +用wait和notify实现简单的生产-消费模式 | 唐佳写字的地方

用wait和notify实现简单的生产-消费模式

一个很简单的waitnotify的例子,wait和sleep的区别是前者会释放锁才进入休眠状态,而后者不释放锁,值得注意的是执行 notify 后,线程并不会立即释放锁,而是要等到退出 synchronized 后才释放锁或者自己主动释放锁(wait())。

+

实验代码:

+
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class ExWaitNotify {
List<Object> products;
int MAX = 50;
public ExWaitNotify(){
products = new ArrayList<>(30);
}
public ExWaitNotify(int num){
products = new ArrayList<>(num);
MAX = num;
}
public void produce(int num){
synchronized (products){
while (true){
if (products.size() <= MAX - num){
System.out.println("当前产品数量: "+products.size()+" 生产者 工作,生产"+num+"个产品");
for (int i = 0; i < num; i++) {
products.add(new Object());
}
}else {
System.out.println("当前产品数量: "+products.size()+" 生产者 唤醒消费者,生产者阻塞");
products.notify();
try {
System.out.println("生产者阻塞,等待");
products.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void consume(int num){
synchronized (products){
while (true){
if (products.size() >= num){
System.out.println("当前产品数量: "+products.size()+" 消费者 工作,消费"+num+"个产品");
for (int i = 0,k = products.size(); i < num; i++,k--) {
// int a =;
// System.out.println(a);
products.remove(k-1);
}
}else {
System.out.println("当前产品数量: "+products.size()+",不够 消费者 一次消费:"+num+" ,消费者 唤醒生产者生产");
products.notify();
try {
System.out.println("消费者阻塞,等待");
products.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
ExWaitNotify exWaitNotify = new ExWaitNotify(50);
Thread produceThread = new Thread(() -> exWaitNotify.produce(20));
produceThread.setName("produce");
Thread consumeThread = new Thread(() -> exWaitNotify.consume(10));
consumeThread.setName("consume");
consumeThread.start();
produceThread.start();
}
}
Share
谈谈线程中断
\ No newline at end of file diff --git "a/2017/02/01/\350\260\210\350\260\210\347\272\277\347\250\213\344\270\255\346\226\255/index.html" "b/2017/02/01/\350\260\210\350\260\210\347\272\277\347\250\213\344\270\255\346\226\255/index.html" new file mode 100644 index 0000000..61fd421 --- /dev/null +++ "b/2017/02/01/\350\260\210\350\260\210\347\272\277\347\250\213\344\270\255\346\226\255/index.html" @@ -0,0 +1,14 @@ +谈谈线程中断 | 唐佳写字的地方

谈谈线程中断

+

最近在写一个多线程爬虫,目前爬了知乎几十万数据,但是我发现我每次停止程序的时候都会造成某些数据不完整,比如说某线程一个问题的答案还没爬完就中断,要做好完美中断(当前数据完整),需要同时控制进程中断和线程中断的,我们可以用SignalHandler捕捉进程kill信号,然后在通过线程中断方法,即可解决,而这篇笔记记一下线程中断。

+
+

线程中断的方式有好几种,简单讨论一下优劣。

+

new Thread().stop();

最粗暴的线程中断方法,直接中断线程,但是已经不建议使用,同一些列的方法还有suspend().resume(),不推荐的原因是因为stop()终结一个线程的时候不能保证锁的释放,可能线程中断了还占用着资源,会造成死锁。

+

自定义stopThread() 方法

思路是设置一个信号标识,对外暴露 stopThread() 方法,该方法的实现是将此标志设为激活状态,在线程需要被中断的时候判断此信号标识是否是激活状态,如果是激活状态,则中断线程。

+

局限性:

+

当线程阻塞或者休眠的时候,判断信号时候激活的代码都没有机会执行,所以自然中断不了线程。

+

stopThread()的升级版 new Thread().interrupt();

为什么说他是stopThread()的升级版呢,因为它和stopThread()的实现思路是一样的,也是为线程设置一个中断标志,告诉线程你可以停止了,然后在安全的地方的手动判断 isInterrupt() 为true 安全中断线程。

+

并且该方法也可以在线程sleep()的时候中断线程,sleep()的时候如果被中断,就会抛出 InterruptedException 异常,我们可以在 catch 块中处理被中断的情况,这个时候如果想要真的中断线程,退出方法,这就是为什么线程sleep非要你手动catch InterruptedException 的原因。

+

先调用 interrupt 方法设置中断标志,因为sleep 抛出异常时会清除中断标志,防止下次进入循环因为没有中断标志而继续执行。

+

Thread.Interrupted()

类的静态方法,判断当前线程的中断状态,但是它跟 new Thread().isInterrupt() 的区别是后者只判断中断标识时候激活,而前者除了判断,还会清除当前中断标志。

+

实验代码:

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
public class ExStopThread{
boolean stopSignal = false;
public void stopThread(){
this.stopSignal = true;
}
// 线程会在第五秒的时候推出方法
public synchronized void stopBySignal(){
int count = 0;
long start = System.currentTimeMillis();
while (true){
while (System.currentTimeMillis() - start >1000){
start = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" is still running "+count);
count++;
}
if(count == 5 && stopSignal == true){
break;
}
}
}
//在第五秒的时候线程休眠或阻塞 并不会退出方法
public synchronized void stopBySignal2(){
int count = 0;
long start = System.currentTimeMillis();
while (true){
while (System.currentTimeMillis() - start >1000){
start = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" is still running "+count);
count++;
}
if(count == 5 && stopSignal == true){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
}
// 改进上述方法 在第五秒的时候 即使sleep 也能被中断
public synchronized void testInterrupt(){
int count = 0;
long start = System.currentTimeMillis();
while (true){
while (System.currentTimeMillis() - start >1000){
start = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" is still running "+count);
count++;
}
if(count == 5 && Thread.currentThread().isInterrupted()){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// e.printStackTrace();
Thread.currentThread().interrupt();
break;
}
break;
}
}
}
// interrupt 并不会推出线程,他只是为线程加上了 中断标志,需要在安全的地方的手动判断 isInterrupt 为true 推出线程。
public synchronized void testInterrupt2(){
int count = 0;
long start = System.currentTimeMillis();
while (true){
while (System.currentTimeMillis() - start >1000){
start = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" is still running "+count);
count++;
}
}
}
public synchronized void testInterrupted(){
int count = 0;
long start = System.currentTimeMillis();
while (true){
while (System.currentTimeMillis() - start >1000){
System.out.println(Thread.interrupted());
start = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+" is still running "+count);
count++;
}
if(count == 5 && Thread.interrupted()){
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
break;
}
break;
}
}
}
public static void main(String[] args) {
ExStopThread exStopThread = new ExStopThread();
Thread threadA = new Thread(()->{
exStopThread.stopBySignal();
exStopThread.testInterrupt();
exStopThread.testInterrupt2();
exStopThread.testInterrupted();
});
threadA.setName("A");
threadA.start();
exStopThread.stopThread();
threadA.interrupt();
Thread.interrupted();
}
}

+
Share
笔记:关于协议和IO的基础
\ No newline at end of file diff --git "a/2017/02/07/\350\260\210\350\260\210\345\255\227\347\254\246/index.html" "b/2017/02/07/\350\260\210\350\260\210\345\255\227\347\254\246/index.html" new file mode 100644 index 0000000..214e202 --- /dev/null +++ "b/2017/02/07/\350\260\210\350\260\210\345\255\227\347\254\246/index.html" @@ -0,0 +1,16 @@ + | 唐佳写字的地方

1.计算机只认识字节

计算机其实只存储和处理字节bit,对它而言,根本没有字符这个概念,字符是给人理解的,也就是说,字符都是在内存中才形成的,在硬盘上只有字节。

+
    +
  • 字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

    2.怎么转换:字符编码

    当计算机把字节和字符转换的时候,势必要有一种规则,这就是字符编码,比如说A,在ASCII编码中对应的数字是65,所以计算机存储的二进制是(0100_0001)。

    3.每个国家有不同的字符集合:字符集

    其实字符编码就是字符到字节的映射规则,但是如果每个国家都有自己的规则就乱了,所以就有了字符集:制定了字符的集合,规定了某个字符对应什么数字(字节)。
  • +
+

所以换个角度看,字符集是规定,字符编码是实现。

+

4. ASCII

ASCII编码规定了一些符号,字母和数字的编码,一共128个,当我们提及ASCII,既表示了一种字符集,也代表了一种字符编码。

+

5. ISO-8859-1(又称Latin-1)

ASCII 编码是美国人制定的,并没有考西欧的一些字母,考虑到一个字节有2的八次方256位,而ASCII只用了低4位,还有高四位没用,于是欧洲采用了ISO-8859-1 编码,该编码在ASCII的基础上,增加了128高四位。

+

6. GBK和GB2312

ISO-8859-1已经1byte可用的位全用完了,其他语言怎么办,于是,中国人决定2个byte来表示他们包含汉字的字符集 GB2312, GB2312zh7000多个字符,对于博大精深的汉字还是不够,于是它的超集 GBK 被制定了。

+

7. Unicode字符集 UTF编码

Unicode字符集指在统一不同国家的字符集。Unicode是一个符号集,它只规定了符号和和对应的二进制编码,他并没有规定二进制编码怎么传输和存储。比如说Unicode字符对应的数字1,你可以用1个字节,也可以用两个字节存储。而这些,是UTF(UCS Transformation Format)做的。

+

UTF: Unicode字符集的编码标准。

+
    +
  • UTF-16: 固定用两个字节表示一个字符
  • +
  • UTF-32: 固定用四个字节表示一个字符
  • +
  • UTF-8:变长字节,用1-4个字节表示一个字符,是互联网传输编码用的最广泛的,隐含了赫夫曼编码思想,用最短的编码表示使用最频繁。
  • +
+
Share
\ No newline at end of file diff --git "a/2017/02/10/\347\254\224\350\256\260-\345\205\263\344\272\216\345\215\217\350\256\256\345\222\214IO\347\232\204\345\237\272\347\241\200/index.html" "b/2017/02/10/\347\254\224\350\256\260-\345\205\263\344\272\216\345\215\217\350\256\256\345\222\214IO\347\232\204\345\237\272\347\241\200/index.html" new file mode 100644 index 0000000..cea8dfd --- /dev/null +++ "b/2017/02/10/\347\254\224\350\256\260-\345\205\263\344\272\216\345\215\217\350\256\256\345\222\214IO\347\232\204\345\237\272\347\241\200/index.html" @@ -0,0 +1 @@ +笔记:关于协议和IO的基础 | 唐佳写字的地方

笔记:关于协议和IO的基础

Share
\ No newline at end of file diff --git a/about/index.html b/about/index.html index 54fec6a..b0859fd 100644 --- a/about/index.html +++ b/about/index.html @@ -1,4 +1,4 @@ - | 唐佳写字的地方

sdasdas -asdasd -asdas -
\ No newline at end of file + | 唐佳写字的地方

follow me on github
+WeChat: Immrtang
+email: immrtang@foxmail.com +
\ No newline at end of file diff --git a/archives/2015/09/index.html b/archives/2015/09/index.html index b7e4c64..9c7d198 100644 --- a/archives/2015/09/index.html +++ b/archives/2015/09/index.html @@ -1 +1 @@ -Archiv | 唐佳写字的地方
\ No newline at end of file +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2015/index.html b/archives/2015/index.html index b7e4c64..9c7d198 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -1 +1 @@ -Archiv | 唐佳写字的地方
\ No newline at end of file +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2016/02/index.html b/archives/2016/02/index.html new file mode 100644 index 0000000..fa22d01 --- /dev/null +++ b/archives/2016/02/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方

2016

\ No newline at end of file diff --git a/archives/2016/03/index.html b/archives/2016/03/index.html new file mode 100644 index 0000000..8d66ba7 --- /dev/null +++ b/archives/2016/03/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2016/04/index.html b/archives/2016/04/index.html index 6f3d42a..49e0f96 100644 --- a/archives/2016/04/index.html +++ b/archives/2016/04/index.html @@ -1 +1 @@ -Archiv | 唐佳写字的地方

2016

\ No newline at end of file +Archive | 唐佳写字的地方

2016

\ No newline at end of file diff --git a/archives/2016/05/index.html b/archives/2016/05/index.html new file mode 100644 index 0000000..dbbfc95 --- /dev/null +++ b/archives/2016/05/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方

2016

\ No newline at end of file diff --git a/archives/2016/06/index.html b/archives/2016/06/index.html new file mode 100644 index 0000000..23617a9 --- /dev/null +++ b/archives/2016/06/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方

2016

\ No newline at end of file diff --git a/archives/2016/07/index.html b/archives/2016/07/index.html index f458627..3cba476 100644 --- a/archives/2016/07/index.html +++ b/archives/2016/07/index.html @@ -1 +1 @@ -Archiv | 唐佳写字的地方

2016

\ No newline at end of file +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2016/08/index.html b/archives/2016/08/index.html new file mode 100644 index 0000000..57f3190 --- /dev/null +++ b/archives/2016/08/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2016/index.html b/archives/2016/index.html index bd8d101..7e2fa68 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -1 +1 @@ -Archiv | 唐佳写字的地方

2016

\ No newline at end of file +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2017/01/index.html b/archives/2017/01/index.html new file mode 100644 index 0000000..4ba6067 --- /dev/null +++ b/archives/2017/01/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2017/02/index.html b/archives/2017/02/index.html new file mode 100644 index 0000000..0cf3526 --- /dev/null +++ b/archives/2017/02/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/2017/index.html b/archives/2017/index.html new file mode 100644 index 0000000..1680d5e --- /dev/null +++ b/archives/2017/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/index.html b/archives/index.html index 1cfc7ca..a5ffbf6 100644 --- a/archives/index.html +++ b/archives/index.html @@ -1 +1 @@ -Archiv | 唐佳写字的地方

2016

2015

\ No newline at end of file +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 0000000..6e84c68 --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1 @@ +Archive | 唐佳写字的地方
\ No newline at end of file diff --git a/index.html b/index.html index ecafab3..8dafdd7 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -唐佳写字的地方

Contaniner

Mehr lesen

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Mehr lesen

哈哈

Mehr lesen

第一篇

asdasd

Mehr lesen

Http,Servlet,Servlet Contaniner

前记:刚学Java Web的时候,大部分人都是先接触的Servlet,然后用web.xml配置了几个小demon,知道了只要在前端中调用后台的方法与配置文件中一致,后台就能请求响应,并传达响应,然后又马上学SSH框架,写了各种xxx.action,xxx.do,对Servlet的原理已经越来越模糊。

Mehr lesen

\ No newline at end of file +唐佳写字的地方

笔记:关于协议和IO的基础

Read More

谈谈线程中断

Read More

用wait和notify实现简单的生产-消费模式

一个很简单的waitnotify的例子,wait和sleep的区别是前者会释放锁才进入休眠状态,而后者不释放锁,值得注意的是执行 notify 后,线程并不会立即释放锁,而是要等到退出 synchronized 后才释放锁或者自己主动释放锁(wait())。

Read More

好无聊啊~写写排序算法?

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
public class ArraySort {
/**
* 直接插入排序 最坏复杂度 n2
* 每一次都插入到一个已排序的序列中 稳定的排序
* @param array
* @return
*/
public static int[] straightInsertionSort(int[] array){
if (array == null){
return array;
}
for (int i = 1;i < array.length; i++) {
for (int j = 0; j < i; j++) {
if (array[i]<array[j]){
int t = array[i];
for (int k = i; k > j; k--) {
array[k] = array[k-1];
}
array[j] = t;
continue;
}
}
}
return array;
}
/**
* 希尔排序 插入排序的一种
* @param array
* @return
*/
public static int[] shellSort(int[] array){
// 增量gap
for (int gap = array.length/2; gap > 1 ; gap/=2) {
// 直接插入排序
for (int i = 0; i < gap; i++) {
for (int j = i+gap; j < array.length; j += gap) {
if (array[j] < array[i]){
// 插入 后面的向后移动
int t = array[j];
// for ()
}
}
}
}
return array;
}
/**
* 平均n*lgn 最坏n2
* @param array
* @return
*/
public static int[] quickSort(int[] array){
quickSort1(array,0,array.length-1);
return array;
}
public static void quickSort1(int[] array,int left,int right){
if (left>=right){
return;
}
int baseValue = array[left];
int baseIndex = left;
while (left<right){
while (array[right] >= baseValue && left < right)
right--;
while (array[left] <= baseValue && left < right)
left++;
swap(array,left,right);
}
// swap(array,baseIndex,left);
array[baseIndex] = array[left];
array[left] = baseValue;
quickSort1(array,baseIndex,left);
quickSort1(array,left+1,right);
}
// public static void quickSort1(int[] array,int start,int end){
// System.out.println(start+" "+end);
// if (start == end){
// return ;
// }
// int i = start + 1;
// int j = end;
// int baseValue = array[start];
// while (i<j){
// while (array[j]>=baseValue){
// j--;
// }
//
// while (array[i]<baseValue && i<j){
// i++;
// }
//
// System.out.println(i+" "+j);
// swap(array,i,j);
// }
// swap(array,start,i);
// quickSort1(array,start,i);
// quickSort1(array,i+1,end);
// }
/**
* 冒泡 n2
* @param array
* @return
*/
public static int[] bubbleSort(int[] array){
if (array == null){
return array;
}
for (int i = 0; i < array.length-1; i++) {
for (int j = array.length-1; j > i; j--) {
if (array[j]<array[j-1]){
swap(array,i,j);
}
}
}
return array;
}
/**
* 选择排序 n2 每次选择最小的 也算冒泡的一种 但是减少了交换次数,只有n-1次交换。
* @param array
* @return
*/
public static int[] selectSort(int[] array){
if (array == null){
return array;
}
for (int i = 0; i < array.length -1; i++) {
int minIndex = i;
for (int j = i+1; j < array.length; j++) {
if (array[minIndex] > array[j]){
minIndex = j;
}
}
if (minIndex != i){
swap(array,i,minIndex);
}
}
return array;
}
/**
* 计数排序 n 但是对数字有要求
* @param array
* @return
*/
public static int[] countSort(int[] array){
int maxIndex = 0;
for (int i = 1; i < array.length; i++) {
if (array[maxIndex] < array[i]){
maxIndex = i;
}
}
int[] array1 = new int[array[maxIndex]+1];
for (int i = 0; i < array.length; i++) {
array1[array[i]]+=1;
}
int[] newArray = array;
int index = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i]; j++) {
newArray[index++] = i;
}
}
return newArray;
}
/**
* 归并排序
* @param array
*/
public static int[] mergeSort(int[] array){
// divice(array,0,array.length-1);
mergeSort1(array,0,array.length-1);
return array;
}
public static void mergeSort1(int[] array,int left,int right){
int mid = (left+right)/2;
if (left<right){
mergeSort1(array,left,mid);
mergeSort1(array,mid+1,right);
mergeArray(array,left,right);
}
}
public static void mergeArray(int[]array,int left,int right){
int[] tmp = new int[right-left+1];
int mid = (left+right)/2;
int index = 0;
int i = left;
int j = mid+1;
while (i<=mid && j<=right){
if (array[i] < array[j]){
tmp[index++] = array[i++];
}else {
tmp[index++] = array[j++];
}
}
// 把左边的放入tmp
while (i<=mid){
tmp[index++] = array[i++];
}
while (j<=right){
tmp[index++] = array[j++];
}
for (int k = 0; k < tmp.length; k++) {
array[left++] = tmp[k];
}
}
// public static void merge(int[] array,int left,)
static void swap(int[] array,int i,int j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void printArray(int[] t){
if (t == null){
System.out.println(t);
return;
}
for (int i = 0; i < t.length; i++) {
System.out.print(t[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] array = RandomUtil.randomIntArray(100,10);
printArray(array);
// int[] array1 = {43, 74, 72, 9, 10, 43 , 93 , 15 ,36 ,0 };
// bubbleSort(array);
// printArray(countSort(array));
printArray(mergeSort(array));
printArray(array);
// printArray(straightInsertionSort(array));
// printArray(array);
}
}

Read More

笔记:关于TCP协议和IO的基础

java nio这块看了很多次,但是每次都是粗浅的看了下大概,导致很多东西回头又忘了,再加上现在nio这块现在容器封装的太深,你在平时根本就没有接触的机会。所以,要能记住不常用的东西,最简单办法就是从底层上理解他。

Read More

也谈谈字符

1.计算机只认识字节

计算机其实只存储和处理字节bit,对它而言,根本没有字符这个概念,字符是给人理解的,也就是说,字符都是在内存中才形成的,在硬盘上只有字节。

Read More

线程 进程 并发 并行

任务调度

线程是什么?要理解这个概念,须要先了解一下操作系统的一些相关概念。大部分操作系统(如Windows、Linux)的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每个任务轮流执行。任务执行的一小段时间叫做时间片,任务正在执行时的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态等待下一个属于它的时间片的到来。这样每个任务都能得到执行,由于CPU的执行效率非常高,时间片非常短,在各个任务之间快速地切换,给人的感觉就是多个任务在“同时进行”,这也就是我们所说的并发(别觉得并发有多高深,它的实现很复杂,但它的概念很简单,就是一句话:多个任务同时执行)

Read More

关于GC

先来看三个问题:

Read More

JVM内存模型

JVM内存图

Read More

String为什么是不可变的

1. 为什么String 是不可变的?

通过查看String的源代码发现,String的底层实现是通过一个 ==private final char[] value==; 也就是一个字符数组实现的,value 是一个引用,一旦指向堆中一个对象实例(数组也是一个对象)就不能再指向其他对象了,并且String并没有提供 setValue 方法,所以无法操作这个数组内存实例,所以String是不可变的。

Read More

\ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 0000000..fc22a61 --- /dev/null +++ b/page/2/index.html @@ -0,0 +1 @@ +唐佳写字的地方

原码反码补码

Q1. 为什么8位带符号的int 取值范围是[-128 ~ 127] ?

Q2. 为什么计算机表示带符号的数值要用补码?

1. 机器数和真值

机器数就是一个数在计算机中的二进制形式,最高位0代表正数,1代表负数。
真值就是这个机器数在计算机中所代表的值
例如:
1000 0001[机器数] = -1 [真值]

Read More

Http,Servlet,Servlet Contaniner

前记:刚学Java Web的时候,大部分人都是先接触的Servlet,然后用web.xml配置了几个小demon,知道了只要在前端中调用后台的方法与配置文件中一致,后台就能请求响应,并传达响应,然后又马上学SSH框架,写了各种xxx.action,xxx.do,对Servlet的原理已经越来越模糊。

Read More

\ No newline at end of file diff --git a/tags/JVM/index.html b/tags/JVM/index.html new file mode 100644 index 0000000..25776b4 --- /dev/null +++ b/tags/JVM/index.html @@ -0,0 +1 @@ +JVM | 唐佳写字的地方

Reading articles in JVM

2016

\ No newline at end of file diff --git "a/tags/Java\345\237\272\347\241\200/index.html" "b/tags/Java\345\237\272\347\241\200/index.html" new file mode 100644 index 0000000..d4255d2 --- /dev/null +++ "b/tags/Java\345\237\272\347\241\200/index.html" @@ -0,0 +1 @@ +Java基础 | 唐佳写字的地方

Reading articles in Java基础

2016

\ No newline at end of file diff --git "a/tags/\344\271\261\345\206\231\347\232\204/index.html" "b/tags/\344\271\261\345\206\231\347\232\204/index.html" index e317478..02ef374 100644 --- "a/tags/\344\271\261\345\206\231\347\232\204/index.html" +++ "b/tags/\344\271\261\345\206\231\347\232\204/index.html" @@ -1 +1 @@ -乱写的 | 唐佳写字的地方

Beiträge in 乱写的

2016

\ No newline at end of file +乱写的 | 唐佳写字的地方

Reading articles in 乱写的

2016

\ No newline at end of file diff --git "a/tags/\345\255\227\347\254\246\347\274\226\347\240\201/index.html" "b/tags/\345\255\227\347\254\246\347\274\226\347\240\201/index.html" new file mode 100644 index 0000000..3caab4e --- /dev/null +++ "b/tags/\345\255\227\347\254\246\347\274\226\347\240\201/index.html" @@ -0,0 +1 @@ +字符编码 | 唐佳写字的地方

Reading articles in 字符编码

2016

\ No newline at end of file diff --git "a/tags/\345\271\266\345\217\221/index.html" "b/tags/\345\271\266\345\217\221/index.html" new file mode 100644 index 0000000..3ffb3cc --- /dev/null +++ "b/tags/\345\271\266\345\217\221/index.html" @@ -0,0 +1 @@ +并发 | 唐佳写字的地方

Reading articles in 并发

2017

\ No newline at end of file diff --git "a/tags/\346\216\222\345\272\217-\347\256\227\346\263\225/index.html" "b/tags/\346\216\222\345\272\217-\347\256\227\346\263\225/index.html" new file mode 100644 index 0000000..27bdaf9 --- /dev/null +++ "b/tags/\346\216\222\345\272\217-\347\256\227\346\263\225/index.html" @@ -0,0 +1 @@ +排序 算法 | 唐佳写字的地方

Reading articles in 排序 算法

2017

\ No newline at end of file diff --git "a/tags/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/index.html" "b/tags/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/index.html" new file mode 100644 index 0000000..215c5a0 --- /dev/null +++ "b/tags/\350\256\241\347\256\227\346\234\272\345\237\272\347\241\200/index.html" @@ -0,0 +1 @@ +计算机基础 | 唐佳写字的地方

Reading articles in 计算机基础

2016

\ No newline at end of file