0%

java之continue,break,goto

先说goto,goto是java中保留关键字,实际并未使用,goto在c中很强大,直接中断当前执行流程跳转到标记所在的流程点开始执行,但是这种能力不好掌控。
java中可以使用continue和break加标签达到类似的效果。

continue

continue在循环内部使用时,中断后面的代码执行,直接开始下一次循环。结合标签使用时,直接执行标签后面的循环代码的下一次循环:

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
public static void main(String[] args) {
//continue单层循环,output:13579
for (int j = 0; j < 10; j++) {
if (j % 2 == 0) continue;//当偶数时跳过后面的执行语句,直接继续increment语句
//打印j
System.out.print(j);
}
System.out.println("\n===========");
//等同上面
outer:
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue outer;
System.out.print(i);
}
System.out.println("\n===========");
outer:
for (int i = 0; i < 5; i++) {
//跳到outer处的increment语句执行
for (int j = i; j < 5; j++) {
if (j % 2 == 0) continue outer;
System.out.println("inner:" + j);
}
//j的循环每次continue到i++,使得此处永不执行
System.out.println("outer:" + i);
}
}

break

break在循环内部使用时,中断后面代码执行并跳出当前循环,执行循环后面的代码,结合标签使用时,表示结束标签后的代码块执行,转而执行后面的代码。

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
//output:012
for (int i = 0; i < 5; i++) {
if(i>2)break;
System.out.print(i);
}

/**
* outer:1
* inner not break:2
* outer:3
*/
for (int i = 0; i < 2; ) {
while (i++<2){
if(i<2) break;//i<2时结束内层循环
System.out.println("inner not break:"+i);
}
System.out.println("outer:"+i);
}

/**
* break-inner[j]:0
* break-inner[j]:1
* break-inner[j]:2
* break-end
*/
outer:
for (int i=0; i <5; i++) {
for (int j = 0; j <5; j++) {
if(i==0&&j==3)break outer;//外层循环第一次执行,内层循环第4次执行时,中断标签后的循环代码块
System.out.println("break-inner[j]:"+j);
}
System.out.println("break-outer[i]:"+i);
}
System.out.println("break-end");

continue和break结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 /**
* level_4[m]-0
* level_2[k]-0
*/
level_1:
for (int j = 0; j <2; j++) {
level_2:
for (int k = 0; k <3; k++) {
if(k==2)break level_1;//k<2时执行level_3
level_3:
for (int l = 0; l <2; l++) {
if (k==1)continue level_2;//只有k=0时执行了
for (int m = 0; m <2; m++) {
if(m==1)break level_3;//只有k=0&&m=0时执行了,当m>0时直接结束了level_3语句块
System.out.println("level_4[m]-"+m);
}
System.out.println("level_3[l]-"+l);
}
//k=0&&m=0执行,之后循环k=1,触发level_3的continue level_2,
//直接k=2,然后触发break level_1,结束整段代码
System.out.println("level_2[k]-"+k);
}
System.out.println("level_1[j]-"+j);
}

抽象类,抽象通用方法

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
/**
* functional describe:selector监听处理方法
*
* @author DR.YangLong [410357434@163.com]
* @version 1.0 2018/7/10
*/
public abstract class AbstractNio {

/**
* 模板方法
*
* @param selector 选择器
* @throws IOException
*/
void listen(Selector selector) throws IOException {
while (true) {
//阻塞,直到有链接
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
handlerKey(key);
}
}
}

/**
* 得到时间通知后具体的处理方法
*
* @param key
* @throws IOException
*/
abstract void handlerKey(SelectionKey key) throws IOException;
}
Read more »

mysql参数说明

转载自MySQL性能调优my.cnf详解 | Linux运维笔记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[client]  
port = 3306
socket = /tmp/mysql.sock

[mysqld]
port = 3306
socket = /tmp/mysql.sock

basedir = /usr/local/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
server-id = 1 #表示是本机的序号为1,一般来讲就是master的意思
Read more »

通用参数

参数 含义 默认值 说明
-server 启用server模式 启用server模式启动时较慢,编译将在启动时完成,在运行时能获得更好的性能
-client 启用client模式 启用client模式,jvm不会对编译阶段优化,启动较快,运行时性能较低
-Xms 初始堆大小 物理内存的1/64(<1GB>) 默认空余堆内存小于40%时(通过MinHeapFreeRatio参数调整),jvm就会增大堆内存,直到为-Xmx的值。
-Xmx 最大堆大小 物理内存的1/4(<1GB) 默认空余堆内存大于70%时(通过MaxHeapFreeRatio参数调整),jvm会减少堆内存,直到-Xms的值。
-Xmn 年轻代大小,jdk>=1.4 不设置此值,年轻代默认为堆的1/3 此值的大小是eden+2个survivor的大小
-XX:NewRatio 年轻代与年老代的比值倒数 2 设为4,表示年轻代:年老代=1:4,年轻代占堆内存1/(4+1),如果设置Xms=Xmx且设置了Xmn,该参数不需要设置
-XX:SurvivorRatio 1个Survivor与Eden的比值倒数 8 设置为6,则Survivo:Eden=1:6,那么2个Survivor总共占年轻代的2/(6+1+1)大小
-XX:PermSize 设置持久代初始大小 物理内存的1/64 JDK1.8之前适用
-XX:MaxPermSize 设置持久代最大值 物理内存的1/4 JDK1.8之前适用
-Xss 每个线程的栈大小 JDK5以后默认为1M,之前为256K 在相同的物理内存下,减少此值能够生成更多的线程,但不会无限生产,受操作系统限制,大小需要根据具体应用设置
-XX:ThreadStackSize 栈深度 根据操作系统不同而不同 设为0表示使用操作系统默认栈深度
-XX:LargePageSizeInBytes 内存页大小 内存页大小不能设置太大,会影响perm大小
-XX:+UseFastAccessorMethods 启用原始类型快速优化
-XX:+DisableExplicitGC 关闭System.gc() 关闭后,代码中调用此方法失效
-XX:MaxTenuringThreshold 对象最大年龄 15 每经过一次垃圾回收,存活下来的对象年龄+1,达到此值时,对象从年轻代移动到年老代,如果设置为0,则对象直接在年老代中分配,该参数只有在串行GC时有效
-XX:+AggressiveOpts 加快编译
-XX:+UseBiasedLocking 启用偏向锁 启用锁优化,在锁低竞争程序中,启用偏向锁有助于性能提升,在锁竞争激烈的程序中,启用偏向锁会降低性能
-Xnoclassgc 禁用垃圾回收
-XX:SoftRefLRUPolicyMSPerMB 每MB空闲空间中软引用的存活时间 1s 默认单位为秒
-XX:PretenureSizeThreshold 对象超过此参数设置的值时直接在年老代分配 0 单位为字节,0时此参数不起作用,且采用Parallel Scavenge GC时无效
-XX:TLABWasteTargetPercent TLAB(Thread-local allocation buffer)占eden区的百分比 1%
-XX:+CollectGen0First full GC前是否先进行一次young GC false
Read more »

map

java实现的map采用散列表的方式,有2个要素构成:桶数组与散列函数。桶数组存储元素,散列函数则确定元素在桶中存放的位置。
在散列表中,为得到较好的性能,需要使每个桶的容量都小于桶的数量,因而引入装载因子,设l为装载因子,n为每个桶的容量,N为桶数组的数量,则:

l=n/N

1
2
3
4
map散列表结构解决碰撞的方法有:
设H为映射的Key通过散列函数计算得到的值,N桶数量(为存储映射的数组的length),L为装载因子=n(每个桶容量)/N。j为正整数(j=1,2,3...)。
1. 开放地址策略。采用开放地址策略的方式是使用数组本身来解决下标冲突,本质都是在遇到碰撞时,将后入的映射向后移动,此策略缺点是性能随元素的增加和碰撞概率(碰撞概率也随元素增加而上升)上升而下降,优点是节省空间,不需要借助额外的空间来解决冲突。线性探测法,遇到碰撞后执行(H+1)%N得到新的下标j,发现j已被占用,再执行(H+2)%N,如此,直到得到的下标能够存入数组。平方探测法,遇到冲突,使用循环(H + j^2)%N的方式直到元素能够存入数组。前2个方法在L大于0.5时,会造成大量元素集聚(线性连续集聚,平方二阶集聚),使得即使存在空桶,也有可能找不到插入的位置。双散列法,除原有散列函数外,再选取另外一个散列函数g()作为二阶散列函数,使得任意g(key)不为0,不断使用H + j*g(key)获取新下标,直到能够存入元素。
2. 分离链策略。分离链策略是将冲突的元素使用链表的形势存储在同一个数组下标处,形成一个列表数据结构,对映射的操作转变为对列表的操作。这种策略下的方法叫做链地址法。此策略缺点是需要额外的空间存储链表,优点是性能稳定且较高。

map存储键值对,有的map允许null值key和value,有的不允许。存取value时通过key判断取值,会涉及key对象的2个方法,equals和hashCode。如果使用重写equals和hashCode方法的类实例化的对象作为key时需要注意可能导致映射不正确(不同的对象会被当成一个对象处理)。如果使用可变对象(修改对象属性值时会对equals产生影响)作为key时,会使映射关系不正确,禁止某个map将自身作为key在自身建立映射。value的equals及hashCode同样影响map对于value的操作。
所有map实现都有2个构造函数,一个默认构造函数,一个以map作为参数的构造函数。
map提供3个视图:key视图(keySet),value视图(values),key-value视图(entrySet)。映射的顺序依赖map的具体实现,由迭代器返回元素的顺序决定。
map基础结构为Entry<K,V>结构。

Read more »

树是一种层次结构。

树的特性:

  1. 树结构中,每个节点的深度都是一个非负整数。
  2. 深度为1的节点有且仅有一个,称作树的根(Root)。
  3. 对于深度为K(k>1)的节点,都有且仅有一个深度为K-1的节点与之对应,称为此节点的父节点。
  4. 若节点B的父节点是A,则B称为A节点的孩子。具有共同父亲的节点之间称为兄弟节点。
  5. 树总是从父亲节点指向孩子节点,形成一条树边。
  6. 树中节点数目总=树边总数+1。
  7. 所有节点中具有最大深度的节点的深度称为树的深度或高度。树的深度,从根节点(深度为1)向下累加,某节点的深度就是根节点累加到此节点(包含)的数值;树的高度,从叶子节点向上累加,父节点的高度就是其深度最深的叶子节点(高度为1)向上累加到它的数值。
  8. 任一节点的孩子总数,称为此节点的度(Degree)。
  9. 树的节点总数=树的节点度数之和*2+1。
  10. 拥有孩子的节点称为内部节点(internal node),没有孩子的节点称为外部节点(external node)或叶子节点(leaf)。
  11. 由树中 k+1 节点通过树边首尾衔接而构成的序列{ (v 0 , v 1 ), (v 1 , v 2 ), …, (v k-1 , v k ) | k ≥ 0},称作树中长度为 k 的一条路径(Path)。
  12. 树中任何2个节点间都存在唯一的一条路径。
  13. 从树根通往任一节点的路径长度,恰好等于该节点的深度-1,即深度=路径长度+1。
  14. 树T中每一节点V的所有后代也构成一棵树,称作T的以V为根的子树(Subtree)。
  15. 在树T中,若在每个节点的所有孩子之间都可以定义某一线性次序,则称T为一棵有序树(Ordered tree)。
  16. 每个内部节点均为m度的有序树,称作m叉树。
Read more »

关于happen-before

原文

  1. Each action in a thread happens-before every action in that thread that comes later in the program’s order.
  2. An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.
  3. A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.
  4. A call to start on a thread happens-before any action in the started thread.
  5. All actions in a thread happen-before any other thread successfully returns from a join on that thread.

整理

  1. 一个线程对monitor解锁之前的所有写操作都对下一个对此monitor加锁的线程可见。即在加锁顺序上,上一个对资源加锁的线程所做的所有操作都对下一个加锁的线程可见。
  2. 如果线程1对volatile变量进行写操作,那么线程1此时及之前的所有写操作(不仅是volatile变量)对后续读取此volatile变量的线程可见。
  3. 线程写入的所有变量,对调用了此线程的jion()方法并成功返回的线程可见。即线程会在join()方法处执行完,且线程写入的变量对调用了此线程join()方法的线程可见。
  4. 线程中上一个写操作及之前的所有写操作在该线程执行下一个动作时对该线程可见。就是在一个单独的线程中,按照程序代码时间顺序执行操作。
  5. 线程的start方法在线程的任何操作之前。
  6. happen before具有传递性,如果存在A>B(>可理解为A happen before B),B>C,则A>C

ubutu不能正确解析域名解决办法

最简单的办法是,系统设置,网络,找到

方法一,修改/etc/resolv.conf

添加

1
2
3
4
5
6
7
8
9
nameserver 223.5.5.5
nameserver 223.6.6.6
nameserver 180.76.76.76
nameserver 202.101.172.35
nameserver 61.153.177.196
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 222.172.200.68
nameserver 61.166.150.123

这个方法重启就会失效。

Read more »

Kernel 4.9+无法安装VMPlayer vmnet问题解决

今天一早升级线上服务器的open ssh,然后升级了下自己的ubuntu,采用的是apt update+upgrade命令。
之后悲剧的发现vmplayer跪了,用度娘找了下,就只有一篇有价值的文章,说在国外论坛看到的,下载了个patch文件。
后来看了看,不适用,最后用手机热点翻墙(公司2M小水管,国内打开网页速度都感人),终于在http://rglinuxtech.com/?p=1838
看到了问题所在和解决方案,在这里重复下解决方案。其他内核版本也可以参照此方法解决。

日志异常

1
2
3
4
5
I125: Setting destination path for vmnet to "/lib/modules/4.9.0-11-generic/misc/vmnet.ko".
I125: Extracting the vmnet source from "/usr/lib/vmware/modules/source/vmnet.tar".
I125: Successfully extracted the vmnet source.
I125: Building module with command "/usr/bin/make -j4 -C /tmp/modconfig-Zu8VZj/vmnet-only auto-build HEADER_DIR=/lib/modules/4.9.0-11-generic/build/include CC=/usr/bin/gcc IS_GCC_3=no"
W115: Failed to build vmnet. Failed to execute the build command.

关键点就是4.9.0-11-generic刚升级的内核,太新了,vm无法识别。

Read more »

git flow入门

软件在开发中的周期为:新功能定义->新功能实现->新功能测试->新功能BUG修复->新功能发布上线->紧急线上bug修复;
使用git的分支以及分支合并可以很好的完成各周期对应的实际操作,但是必须熟知git命令并且规范性比较差,git flow是一个基于git的工作流规范工具。
它集成了git的分支,tag等命令,整合为软件开发周期中的各个阶段,可以很容易就实现软件的规范化开发。
基本流程图(来源于博客ngulc,不再重复画了):
FLOW

Read more »