0%

前言

linux Awk 脚本语言,算来也有很长的一段历史了。在如今各种更全更简单的脚本语言遍地生成的年代,关注Awk的新人越来越少了。最近,在项目组同事的影响下,去学习了下Awk的基本使用方法。

Note:本文只是学习笔记,很多示例和描述都来自最后推荐的文章里面。

起意写关于Awk学习笔记的主要原因是,学习皓哥的AWK 简明教程 完了之后,完全还是云里雾里的,不知所以然。所以,找了个AWK 手册好好学习。但是,对于前者介绍太多浅,初学者对于Awk使用没有任何概念;后者又过于长,不方便我去查资料,所以合计起来,就写一个学习总结罢了。

Awk命令行

关于Awk的历史,语言优势什么的,就不浪费时间介绍了。

2.1 Awk 程序结构

首先,我们在服务器上查看日志信息,大部分时候都希望使用一行命令搞定问题,因此,显然命令行方式使用Awk是很频繁的事情。

1
awk 'awk程序主体' [操作的文本] 

在写一个awk脚本之前,首先需要的是了解 awk程序组成结构,如果你不了解它的程序一般的结构,那么你去看皓哥或者其他人写的入门级Awk小程序,你也无法真正去了解或者深入。

Pattern1 {Actions1}
Pattern2 { Actions2 }
......
Pattern3 { Actions3 }
阅读全文 »

前言

前段时间,查看线上Tomcat日志,发现多台服务器出现Mysql死锁情况,虽然死锁问题没有影响到正常业务,但是毕竟数据库死锁还是得需要好好分析原因去修复和开发过程中极力需要避免的。服务器上Mysql死锁日志如下:

由于我们的服务使用了连接池,所以接着让 DBA 查询下Mysql的数据库操作日志信息,如下图所示:

死锁问题定位

查看了建表语句,其实很简单:

1
2
3
4
5
6
CREATE TABLE `room_rate_plan_id` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`value` varchar(100) NOT NULL ,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_value` (`value`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=175663 DEFAULT CHARSET=utf8

而使用的地方只在一个类代码里用过,使用的方式是select for update,并且该查询事务中包含着,如果不存在,则INSERT INTO room_rate_plan_id (value) VALUES(?)语句,那么,接着就得了解select for update来确定是不是这里导致数据库死锁现象。主要有两篇博客:

阅读全文 »

前言

使用 JVM的人都或多或少的了解垃圾回收机制,当系统的服务出现性能问题时,都会去服务器上查看下系统GC的情况。此外,如果有新的服务上线,也需要去服务器上查看下新服务的整体GC水平,这就可以使用jstat命令来查看了,当然你也可以使用其他方式。

Jstat 查看系统 GC 命令介绍

jstat的命令查看系统GC情况,很简单,只需要先通过jps或者ps -aux |grep tomcat来查看对应服务所在的进程数,然后使用下面命令查看。

jstat 查看 gc 使用方法如下:

1
2

jstat -gcutil `线程值` `间隔时间数(ms)`

执行命令sudo jstat -gcutil 11694 3600,结果会显示内存各个区域大小的情况,如图:

Note: 结果里面列出每个区间的内存大小,新生代gc的次数和时间,老年代gc的次数和时间。

1. S0  — Heap上的 Survivor space 0 区已使用空间的百分比;
2. S1  — Heap上的 Survivor space 1 区已使用空间的百分比;
3. E   — Heap上的 Eden space 区已使用空间的百分比;
4. O   — Heap上的 Old space 区已使用空间的百分比;
5. P   — Perm space 区已使用空间的百分比;
6. YGC — 从应用程序启动到采样时发生 Young GC 的次数;
7. YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒);
8. FGC — 从应用程序启动到采样时发生 Full GC 的次数;
9. FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒);
10. GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒).
阅读全文 »

前言

走入社会工作接近一年了,感慨颇多.一年前的现在,自己对java知之甚少,更不知道怎么去创建一个满足spring mvc架构思想的web项目。最近,为了学习Spring MVC框架的实现原理,首先新建了一个web项目,该项目包含 Spring + Mybatis涉及数据库,DAO,service,API,业务,controller多个模块。

Note:这个项目代码完成的功能只是为了演示一个大项目应该具备的结构,而显然在实际工程中,这么简单地功能,是不需要如此繁杂的结构模块的。

此外,关于Spring MVC演示项目的代码,可以从githubclone一份到本地,项目为:SimpleSpringProjectgit clone 地址为:https://github.com/ketao1989/simpleSpringProject.git

SimpleSpringProject 结构介绍

simpleSpringProject项目各个模块分工明确,主要由8个模块组成:

1. simple-spring-main模块:该模块主要是提供给外界访问的controller层所在。`controller`层可以对外提供html视图,也可以对外提供RPC调用,例如 alibaba 的 dubbo接口。

2. simple-spring-api模块:该模块主要就是封装一些底层的方法接口给外部使用。比如,如果我们使用RPC接口调用服务,则只需要API包就可以了,具体实现调用方是不需要知道的。

3. simple-spring-biz模块:该模块是业务模块,也就是具体业务需要的方法基本上都是在这里实现的。在demo 中,在这一层实现api提供的接口。该模块主要调用service层提供的基本服务,组装起来,实现各种不同的业务逻辑接口。

4. simple-spring-service模块:该模块是基础服务模块,该模块会为biz业务模块提供基本的服务,这些服务功能都比较简单,业务逻辑单一。因此,在这一层进行单元测试,一般会取到比较好的效果。

5. simple-spring-dao模块:该模块是数据库相关接口模块。`Mybatis`可以把interface 和 xml结合起来,使得开发者可以把数据库表中相关操作集成在 interface 代码中,而具体的`SQL`实现则写在xml文件中。这样子,可以让整个结构更清晰。

6. simple-spring-config模块:该模块就是相关`sql`语句的配置文件所在地。一般地,会根据interface 来切分不同的配置文件,两种的关联关系是通过对于的`sql.xml`文件中`mapper namespace`来关联。

7. simple-spring-common模块:该模块一般存放一些项目公用的工具类和常量值。比如,一些配置文件中需要配置的属性值,一些xxxUtils类实现等。

8. simple-spring-model模块:该模块主要提供一些模型,各个类需要使用的对象。比如,我们需要获取一个学生个体信息,显然会作为一个对象类来实现。

Note:显然,对于各个模块的具体详细分工,其实还是可以调整的,比如可能有些地方会在service层来做稍微复杂的服务实现,而在biz层则稍微组合就可以了。这里,demo的模块分类,只是正常情况下,业务规模有一些大的情况下,才会进行多个模块的分工。

阅读全文 »

前言

在并发编程网上,关于ForkJoin框架介绍得很好,推荐去看: Fork/Join框架 本篇博文只是对一些地方进行补充说明(为了文章连续性,会借鉴一些介绍文字).

在上一篇博文: Java 多线程线程池介绍 中最后说明了,对于一个任务可以切割成多个小任务分别执行,然后把各个小任务的结果,组合成最终的结论。熟悉MapReduce的同学,肯定对此再熟悉不过了。

首先贴出一个很简单的代码demo,这段代码是对上篇博文中代码,用ForkJoin API方式来实现(实际上,这并不是一个好的介绍ForkJoin功能的例子,但是我们先用它来入门了)

ForkJoin任务,继承自RecursiveAction,因为我们不需要任务返回什么计算结果:

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

package io.github.ketao1989;

import java.util.List;
import java.util.concurrent.RecursiveAction;

/**
* 很简单的一个操作,就是把字符串加一个后缀,然后放进队列里
*
* @author: ketao Date: 14-5-24 Time: 下午10:16
* @version: \$Id$
*/
public class ListTask extends RecursiveAction {

private static final int THRESHOLD = 1;

private List<String> processStr;
private int start;
private int end;

public ListTask(List<String> processStr, int start, int end) {
this.processStr = processStr;
this.start = start;
this.end = end;
}

@Override
protected void compute() {
boolean isProcess = (end - start) == THRESHOLD;
if (isProcess) {
System.out.println(Thread.currentThread().getName());
String newStr = processStr.get(start) + "-test";
processStr.set(start, newStr);

} else {
System.out.println(Thread.currentThread().getName()+"----");
int partPos = (start + end) / 2;
ListTask taskl = new ListTask(processStr, start, partPos);
ListTask taskr = new ListTask(processStr, partPos, end);
invokeAll(taskl, taskr);
}
}

}
阅读全文 »

前言

关于Java多线程的知识,看了很多博客书籍,对理论还是比较了解的。但是,最近写一个很简单的使用线程池对列表中任务进行处理,然后返回结果列表的功能,发现理论和实际操作还是有相当大的差距。

首先贴出一个很简单的代码demo:

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
/**
* @author: ketao Date: 14-5-3 Time: 下午4:51
* @version: \$Id$
*/
public class ThreadTest {

private static final ExecutorService executors = Executors.newFixedThreadPool(2);

public static void main(String[] args) {

List<String> list = Lists.newArrayList("thread-1", "thread-2", "thread-3", "thread-4");
final List<String> results = Collections.synchronizedList(new ArrayList<String>());
for (final String str : list) {
executors.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
results.add(str+"test");
System.out.println(Thread.currentThread().getName());

}
});
}

System.out.println(JSON.toJSONString(results));
executors.shutdown();
}
}

执行结果如下,显然results的值并不是我们想要的结果

[]
pool-1-thread-1
pool-1-thread-2
pool-1-thread-2
pool-1-thread-1

1.1 线程定义

来自Java 并发大家 Doug Lea 关于线程的描述(中文版):

线程:其是一个独立执行的调用序列,同一个进程的线程在同一时刻共享一些系统资源(比如文件句柄等)也能访问同一个进程所创建的对象资源(内存资源)。

由于一般的系统,最小的基本调度单位是线程,因此如果一个程序中只有一个线程的话,当该线程因为远程调用或者数据库访问,或者其他大量数学计算导致IO/CPU阻塞时,就会导致整个处理性能大幅度的降低。即使没有这些阻塞,对于当前多核处理系统来讲,单线程也会导致资源的浪费。因此,多线程可以帮助我们很好地提高系统的处理能力和吞吐能力。

Java线程API

在Java中可以通过java.lang.Thread创建线程。一般,应用中包括两种类型的线程:用户线程和守护线程。当应用启动时,会创建main线程,然后main线程可以创建多个用户线程和守护线程。当所有的用户线程都终止的时候,则JVM会终止程序。
相对于用户线程而言,守护线程是为用户线程服务的,当所有的用户线程都退出的时候,守护线程就会全部退出,而不管守护线程当前的执行任务是否完成。

2.1 创建Thread

在java中,创建一个线程类对象很简单,有两种方式:其一,只需要继承Thread类,并且在子类中实现run()方法;其二,实现一个Runnable接口来创建线程。简单地demo如下:

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
/**
* @author: ketao Date: 14-5-3 Time: 下午4:51
* @version: \$Id$
*/
public class ThreadTest {

public static void main(String[] args) {

System.out.println(Thread.currentThread().getName()); // main

Thread thread = new Thread(){
public void run(){
System.out.println("创建一个java线程");
System.out.println(Thread.currentThread().getName()); // Thread-0
}
};

thread.start();

Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("创建一个java线程");
System.out.println(Thread.currentThread().getName()); // Thread==Runable=2
}
},"Thread==Runable=2");
thread1.start();
}
}
阅读全文 »

前言

slf4j:简洁的java日志统一接口(Simple Logging Facade for Java),顾名思义,就是一个使用Facade设计模式实现的面向java Logging框架的接口开源包.
其和java数据库连接工具包JDBC很像, 在JDBC框架中, 各个不同数据库连接器分别针对不同数据库系统来实现对应的连接操作, 而普通程序员只需要使用统一的JDBC接口而不需要关注具体底层使用的数据库类型, 或者针对不同的数据库系统写各种兼容代码.

Note: slf4j其实类似于适配器,但是这里不称呼适配器,是因为当底层log日志系统不支持slf4j扩展时,比如log4j,就需要在两者中间增加一个适配器层来完成slf4j调用相关日志系统的操作接口动作.例如,slf4j为log4j提高的slf4j-log412.jar类库,但是logback支持slf4J扩展,所以其不需适配层转换.

同样,slf4j 不参与具体的日志代码实现,它只是在代码编译的时候根据程序的配置来绑定具体的日志系统。这样,使用slf4j类库就可以让你的代码独立于任意一个特定的日志API。因此,如果编写一个对外开发的API活着一个同样的类库,那么为了不限制使用你类库的代码必须使用指定的日志系统,你应该使用slf4j。

相对于其他日志框架,slf4j日志类库的优点和推荐使用的缘由,可以参见 ImportNew 的译文【 为什么要使用SLF4J而不是Log4J

Facade设计模式简介

Facade模式,或者叫做外观模式,顾名思义就是封装各个底层子系统的提供的同一类功能接口,统一成一个更易操作使用的上层接口进而对外提供交互。有了这个上层封装的接口,接口调用方只需要调用这个接口,而不需要关于各个子系统的具体逻辑实现。

Facade设计模式的官方定义是:Facade模式定义了一个更高层的接口,使子系统更加容易使用。

阅读全文 »

前言

在很多情况下,我们在本地启动调试一些服务;或者说外部调用开发测试环境某些服务时,需要直接调试定位问题代码点;
这些问题都会让我们需要可以在本地IDE上面调试本地代码来查看线上情况。最近和其他业务部门联调的时候,
了解到原来真的可以debug本地代码同步控制线上运行流程。下面,记录一下具体的操作配置步骤。

线上服务配置

目前线上的整个tomcat的服务脚本配置:

  1. 一台机器上放一个全局脚本,比如放置在/home/tomcat/bin目录下;
  2. 机器上的每一个tomcat实例目录里面都会有一些基本的设置,比如tomcat的conf目录,以及startenv.sh文件,
  3. startenv.sh文件目前的配置为:
1
2
3
4
5
6
7
export TOMCAT_USER="tomcat"
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:NewSize=256m -XX:PermSize=256m -server -XX:+DisableExplicitGC -Dqunar.logs=$CATALINA_BASE/logs -Dqunar.cache=$CATALINA_BASE/cache -verbose:gc -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:$CATALINA_BASE/logs/gc.log"
chown -R tomcat:tomcat $CATALINA_BASE/logs
chown -R tomcat:tomcat $CATALINA_BASE/cache
chown -R tomcat:tomcat $CATALINA_BASE/conf
chown -R tomcat:tomcat $CATALINA_BASE/work
chown -R tomcat:tomcat $CATALINA_BASE/temp
阅读全文 »

说明:来自互联网,如有版权问题,请告知本人将其撤下。

前言

这份文档是Google Java编程风格规范的完整定义。当且仅当一个Java源文件符合此文档中的规则,
我们才认为它符合Google的Java编程风格。

与其它的编程风格指南一样,这里所讨论的不仅仅是编码格式美不美观的问题,
同时也讨论一些约定及编码标准。然而,这份文档主要侧重于我们所普遍遵循的规则,
对于那些不是明确强制要求的,我们尽量避免提供意见。

1.1 术语说明

在本文档中,除非另有说明:

  1. 术语class可表示一个普通类,枚举类,接口或是annotation类型(@interface)
  2. 术语comment只用来指代实现的注释(implementation comments),我们不使用“documentation comments”一词,而是用Javadoc。

其他的术语说明会偶尔在后面的文档出现。

1.2 指南说明

本文档中的示例代码并不作为规范。也就是说,虽然示例代码是遵循Google编程风格,但并不意味着这是展现这些代码的唯一方式。
示例中的格式选择不应该被强制定为规则。

阅读全文 »