Hello Coder


  • 首页

  • 归档

  • 标签

  • 搜索
close

mysql优化

发表于 2017-03-07

Thread中start()和run()的区别

发表于 2017-03-03

start() 和 run()的区别示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 最常见的两种方法启动新的线程
public static void startThread() {
// 1) 覆盖 run 方法
new Thread() {
@Override
public void run() {
// 耗时操作
}
}.start();
// 2) 传入 Runnable 对象
new Thread(new Runnable() {
public void run() {
// 耗时操作
}
}).start();
}

start() 和 run()相关源码

Thread.java中start()方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public synchronized void start() {
// 如果线程不是"就绪状态",则抛出异常!
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 将线程添加到ThreadGroup中
group.add(this);
boolean started = false;
try {
// 通过start0()启动线程
start0();
// 设置started标记
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}

说明:start()实际上是通过本地方法start0()启动线程的。而start0()会新运行一个线程,新线程会调用run()方法。

1
private native void start0();

Thread.java中run()的代码如下:

1
2
3
4
5
public void run() {
if (target != null) {
target.run();
}
}

说明:target是一个Runnable对象。run()就是直接调用Thread线程的Runnable成员的run()方法,并不会新建一个线程。

参考:

https://github.com/xcc3641/hexo_blog/blob/master/source/_posts/Review-Java-Thread-1.md

http://www.jianshu.com/p/81a56497e073

Java8环境下的Maven javadoc插件的配置

发表于 2017-03-02

问题

用maven在mvn clean package时,出现新的问题:生成javadoc出现异常,导致打包失败。

1
2
3
4
5
6
ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.10.1:jar (default) on project ticket-business: MavenReportException: Error while creating archive:
[ERROR] Exit code: 1 - /Users/nali/Documents/workspace/ticket/ticket-business/src/main/java/com/ximalaya/ticket/business/dao/ticket/TicketProductMapper.java:13: 错误: 未知标记: mbg.generated
[ERROR] * @mbg.generated Wed Mar 01 20:02:30 CST 2017
[ERROR] ^
[ERROR] /Users/nali/Documents/workspace/ticket/ticket-business/src/main/java/com/ximalaya/ticket/business/dao/ticket/TicketProductMapper.java:15: 警告: example没有 @param
[ERROR] long countByExample(TicketProductExample example);

配置

javadoc的插件pom.xml配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
<goal>javadoc</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>

排查

回退java版本到java7, 结果如下:

1
[WARNING] /Users/nali/Documents/workspace/ticket/ticket-business/src/main/java/com/ximalaya/ticket/business/model/TicketUser.java:172: 警告 - @mbg.generated是未知标记。

可以发现在java7中是可以通过的,而在java8中则会报错。

应该是java8加了对javadoc的新的特性,查看Java8的特性列表吧。果然,Java8添加了一个Javadoc注释内容检查的特性DocLint。

DocLint提供了一种方法来检测Javadoc的注释中的错误,希望能够在开发周期的早期和容易链接回源代码的方式。

解决

1) 忽略注释错误

如果想忽略DocLint的使用,可以在maven-javadoc-plugin的配置中加上对DocLint的忽略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
<goal>javadoc</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</plugin>

或者在控制台输出:

1
mvn clean install -Dadditionalparam=-Xdoclint:none

2) 跳过javadoc生成

控制台输出:

1
mvn clean install -Dmaven.javadoc.skip=true

参考:

https://tonydeng.github.io/2015/10/21/maven-Javadoc-plugin-in-java8-exception-resolution/

http://openjdk.java.net/jeps/172

Quartz 原理

发表于 2017-02-28

一、Quartz 基本介绍

1.1 Quartz特点

​ Quartz 具有以下特点:

  1. 强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
  2. 灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
  3. 分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。

​ 另外,作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能。

quartz调度核心元素:

  1. Scheduler: 任务调度器,是实际执行任务调度的控制器。在spring中通过SchedulerFactoryBean封装起来。
  2. Trigger:触发器,用于定义任务调度的时间规则,有SimpleTrigger,CronTrigger,其中CronTrigger用的比较多。CronTrigger在spring中封装在CronTriggerFactoryBean中。
  3. JobDetail: 用来描述Job实现类及其它相关的静态信息,如Job名字、关联监听器等信息。在spring中有JobDetailFactoryBean和 MethodInvokingJobDetailFactoryBean两种实现,如果任务调度只需要执行某个类的某个方法,就可以通过MethodInvokingJobDetailFactoryBean来调用。
  4. Job: 是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。实现Job接口的任务,默认是无状态的,若要将Job设置成有状态的,在quartz中是给实现的Job添加@DisallowConcurrentExecution注解(以前是实现StatefulJob接口,现在已被Deprecated),在与spring结合中可以在spring配置文件的job detail中配置concurrent参数。
  5. QuartzSchedulerResources:相当于调度的资源存放器,包含了JobStore, ThreadPool等资源,调度都是通过 QuartzSchedulerResources获取相关属性的。

实现一个最简单的 Quartz 定时任务(不支持多机),有几个步骤:

  1. 创建 Job。
  2. 创建 JobBuilder。顾名思义,可以用于生成 JobDetail 。
  3. 创建 TriggerBuilder。作用:配置定时时间,可以用于生成 Trigger 。
  4. 创建 Scheduler。作用:启动定时任务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class HelloJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello World");
}
public static void main(String[] args) throws Exception {
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("dummyJobName", "group1").build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("dummyTriggerName", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
}

1.2 Quartz 集群配置

quartz集群是通过数据库表来感知其他的应用的,各个节点之间并没有直接的通信。只有使用持久的JobStore才能完成Quartz集群。
数据库表:以前有12张表,现在只有11张表,现在没有存储listener相关的表,多了QRTZ_SIMPROP_TRIGGERS表:

Table name Description
QRTZ_CALENDARS 存储Quartz的Calendar信息
QRTZ_CRON_TRIGGERS 存储CronTrigger,包括Cron表达式和时区信息
QRTZ_FIRED_TRIGGERS 存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息
QRTZ_PAUSED_TRIGGER_GRPS 存储已暂停的Trigger组的信息
QRTZ_SCHEDULER_STATE 存储少量的有关Scheduler的状态信息,和别的Scheduler实例
QRTZ_LOCKS 存储程序的悲观锁的信息
QRTZ_JOB_DETAILS 存储每一个已配置的Job的详细信息
QRTZ_SIMPLE_TRIGGERS 存储简单的Trigger,包括重复次数、间隔、以及已触的次数
QRTZ_BLOG_TRIGGERS Trigger作为Blob类型存储
QRTZ_TRIGGERS 存储已配置的Trigger的信息
QRTZ_SIMPROP_TRIGGERS

QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,包括以下几个锁:CALENDAR_ACCESS 、JOB_ACCESS、MISFIRE_ACCESS 、STATE_ACCESS 、TRIGGER_ACCESS。

阅读全文 »

Mockito 源码解析

发表于 2017-02-24

Mockito是Java平台上超火的Mock框架,因为其便捷的API,深受广大开发者喜爱。本文将从源码的角度,来分析Mockito的运行流程。

Mockito 简介

Mockito类相当于整个框架的门面,负责对外提供调用接口。常用的有如下几个:

  • mock

    1
    List list = Mockito.mock(List.class); 此时, list就是被Mockito所mock后生成的实例,Mockito会记住它所mock对象的所有调用,为后面的验证做准备。
    • 默认情况下,调用mock对象的带返回值的方法会返回默认的值,比如返回null、0值或者false等。
    • 允许多次代理mock对象的同一个方法,但具体的行为取决于该方法最近的一次代理行为。
    • mock对象的代理方法,允许多次调用,只有不覆盖它的代理行为,那么每次调用的执行相同的行为或者返回相同的值
    • 相同的方法和参数唯一确认一个代理。比如你可以分别代理get(int)方法在参数分别为0和1时的不同行为。
  • when

    1
    Mockito.when(list.size()).thenReturn(1);

    上述代码表示,当对list对象调用size()方法时,会返回1.这样我们就可以自定义mock对象的行为了。

    java 中的程序调用是以栈的形式实现的,对于 when 方法,list.size() 方法的调用对它是不可见的。when 能接收到的,只有 list.size() 的返回值。

  • verify

    1
    Mockito.verify(list).add(Matchers.anyObject());

    verify是负责验证的函数,接受的参数是一个被mock的对象,表示验证其是否执行了后面的方法。

Mockito 实现

Mock 使用了代理模式。我们操作的list,实际上是继承了List的代理类的实例,我们把它称为 proxy 对象。因此对于list 的所有操作,都会先经过 proxy 对象。

Mocktio 就是通过这种方式,拦截到了list 的所有操作。只要在调用list 的方法时,将该方法存放起来,然后在调用 thenReturn 为其设置返回值就可以了。

类图

img

几个主要的类已用红颜色标出,它们将会是Mockito的核心,也是下文主要介绍的对象。接下来,就深入Mockito的源码来一探究竟。

阅读全文 »
1…151617…31
David

David

Develop Notes

155 日志
37 标签
GitHub Weibo
© 2016 - 2020 David
由 Hexo 强力驱动
主题 - NexT.Pisces