Thread中start()和run()的区别
start() 和 run()的区别示例
|
|
start() 和 run()相关源码
Thread.java中start()方法的源码如下:
|
|
说明:start()实际上是通过本地方法start0()启动线程的。而start0()会新运行一个线程,新线程会调用run()方法。
|
|
Thread.java中run()的代码如下:
|
|
说明:target是一个Runnable对象。run()就是直接调用Thread线程的Runnable成员的run()方法,并不会新建一个线程。
参考:
https://github.com/xcc3641/hexo_blog/blob/master/source/_posts/Review-Java-Thread-1.md
Java8环境下的Maven javadoc插件的配置
问题
用maven在mvn clean package时,出现新的问题:生成javadoc出现异常,导致打包失败。
|
|
配置
javadoc的插件pom.xml配置如下:
|
|
排查
回退java版本到java7, 结果如下:
|
|
可以发现在java7中是可以通过的,而在java8中则会报错。
应该是java8加了对javadoc的新的特性,查看Java8的特性列表吧。果然,Java8添加了一个Javadoc注释内容检查的特性DocLint。
DocLint
提供了一种方法来检测Javadoc的注释中的错误,希望能够在开发周期的早期和容易链接回源代码的方式。
解决
1) 忽略注释错误
如果想忽略DocLint
的使用,可以在maven-javadoc-plugin
的配置中加上对DocLint
的忽略。
|
|
或者在控制台输出:
|
|
2) 跳过javadoc生成
控制台输出:
|
|
参考:
https://tonydeng.github.io/2015/10/21/maven-Javadoc-plugin-in-java8-exception-resolution/
Quartz 原理
一、Quartz 基本介绍
1.1 Quartz特点
Quartz
具有以下特点:
- 强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;
- 灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;
- 分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。
另外,作为 Spring 默认的调度框架,Quartz 很容易与 Spring 集成实现灵活可配置的调度功能。
quartz调度核心元素:
- Scheduler: 任务调度器,是实际执行任务调度的控制器。在spring中通过
SchedulerFactoryBean
封装起来。 - Trigger:触发器,用于定义任务调度的时间规则,有
SimpleTrigger
,CronTrigger
,其中CronTrigger用的比较多。CronTrigger在spring中封装在CronTriggerFactoryBean中。 - JobDetail: 用来描述Job实现类及其它相关的静态信息,如Job名字、关联监听器等信息。在spring中有
JobDetailFactoryBean
和MethodInvokingJobDetailFactoryBean
两种实现,如果任务调度只需要执行某个类的某个方法,就可以通过MethodInvokingJobDetailFactoryBean
来调用。 - Job: 是一个接口,只有一个方法
void execute(JobExecutionContext context)
,开发者实现该接口定义运行任务,JobExecutionContext
类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap
实例中。实现Job接口的任务,默认是无状态的,若要将Job设置成有状态的,在quartz中是给实现的Job添加@DisallowConcurrentExecution
注解(以前是实现StatefulJob接口,现在已被Deprecated),在与spring结合中可以在spring配置文件的job detail中配置concurrent参数。 - QuartzSchedulerResources:相当于调度的资源存放器,包含了JobStore, ThreadPool等资源,调度都是通过 QuartzSchedulerResources获取相关属性的。
实现一个最简单的 Quartz 定时任务(不支持多机),有几个步骤:
- 创建 Job。
- 创建 JobBuilder。顾名思义,可以用于生成 JobDetail 。
- 创建 TriggerBuilder。作用:配置定时时间,可以用于生成 Trigger 。
- 创建 Scheduler。作用:启动定时任务。
|
|
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 源码解析
Mockito是Java平台上超火的Mock框架,因为其便捷的API,深受广大开发者喜爱。本文将从源码的角度,来分析Mockito的运行流程。
Mockito 简介
Mockito类相当于整个框架的门面,负责对外提供调用接口。常用的有如下几个:
mock
1List list = Mockito.mock(List.class); 此时, list就是被Mockito所mock后生成的实例,Mockito会记住它所mock对象的所有调用,为后面的验证做准备。- 默认情况下,调用mock对象的带返回值的方法会返回默认的值,比如返回null、0值或者false等。
- 允许多次代理mock对象的同一个方法,但具体的行为取决于该方法最近的一次代理行为。
- mock对象的代理方法,允许多次调用,只有不覆盖它的代理行为,那么每次调用的执行相同的行为或者返回相同的值
- 相同的方法和参数唯一确认一个代理。比如你可以分别代理get(int)方法在参数分别为0和1时的不同行为。
when
1Mockito.when(list.size()).thenReturn(1);上述代码表示,当对list对象调用size()方法时,会返回1.这样我们就可以自定义mock对象的行为了。
java 中的程序调用是以栈的形式实现的,对于 when 方法,list.size() 方法的调用对它是不可见的。when 能接收到的,只有 list.size() 的返回值。
verify
1Mockito.verify(list).add(Matchers.anyObject());verify是负责验证的函数,接受的参数是一个被mock的对象,表示验证其是否执行了后面的方法。
Mockito 实现
Mock 使用了代理模式。我们操作的list,实际上是继承了List
的代理类的实例,我们把它称为 proxy 对象。因此对于list 的所有操作,都会先经过 proxy 对象。
Mocktio 就是通过这种方式,拦截到了list 的所有操作。只要在调用list 的方法时,将该方法存放起来,然后在调用 thenReturn 为其设置返回值就可以了。
类图
几个主要的类已用红颜色标出,它们将会是Mockito的核心,也是下文主要介绍的对象。接下来,就深入Mockito的源码来一探究竟。