Java-log4j自定义日志文件-带import包
在网上找了一些关于log4j自定义包的方法,然而因为说明都没有带import说明,导致找到正确的包费了不少功夫。
在网上找了一些关于log4j自定义包的方法,然而因为说明都没有带import说明,导致找到正确的包费了不少功夫。
javaMap的4种遍历方式
在Java中一个很便利的东西就是注解,而注解中最最核心就是注解执行器,而理解注解执行器就涉及到Java的反射原理。
为此,我们来通过简单的程序来了解Java反射是如何应用的。
Java是静态语言,但是Java的反射原理使得Java具有的动态性。
使用Java的反射,不需要引入任何额外的jar包或者是maven依赖,在其基本的JDK中就有,其路径为:com.lang.reflect
。
如下所示,有一个简单的类:Student
1 | package com.qw.reflect; |
我们现在通过反射获取其内部属性,并打印名称,程序如下:
1 | public static void main(String[] args) { |
而且,特别需要注意到的是,上述代码中,我们声明的参数s
是一个父类型Object
,还不是子类型。当然,设置s
为子类型的时候也可以获取到。
com.lang.reflect.Class
先来熟悉一下反射中常用的方法:如获取类的全名,通过反射创建类的对象等等。
1 | Object o = new Student(); |
最终的输出结果为:
1 | com.qw.reflect.Student |
getSimpleName
返回了最简单的类名,而其他方法返回的均为包含“包”路径的类名,专业名称为:“完全限定类名”。
反过来,知道了类的完整类名,我们能否创建类的对象呢?方式如下所示:
1 | Class<?> clazz1 = Class.forName("com.qw.reflect.Student"); |
输出效果如下(实际上和上一端完全一样)
1 | com.qw.reflect.Student |
java.lang.reflect.Modifier
Modifier为修饰符类,可以帮助我们获取类的修饰符,使用样例如下:
1 | Class<?> clazz1 = Class.forName("com.qw.reflect.Student"); |
借助反射包中的类,我们可以获取对象的包信息,父类信息,所实现的接口信息等等,也能够获取类的构造器Constructor,类中的属性域Field,以及类中的方法Method。
其中需要注意的一点是,在反射中,获取父类或所实现的接口时,仅限于其直接使用implements
实现的接口,即在代码中直接写明的实现接口,而通过父类继承,实现的接口不会在反射中获取。
因为我本人更关心添加在方法上的注解,所以我也更关心在反射中对于方法的调用与获取。我们来看看如何通过反射调用类中的方法。
为此,我们给上面例子中的Student类添加一下方法:
1 | package com.qw.reflect; |
先来尝试获取一下类的方法:
1 | Class<?> clazz1 = Class.forName("com.qw.reflect.Student"); |
输出结果:
1 | isYoung |
我们发现,除了Student本身的方法外,其继承的Object类中的方法也都被打印了出来。为了规避Object类的方法,我们可以使用getDeclaredMethods()
方法,如下:
1 | Class<?> clazz1 = Class.forName("com.qw.reflect.Student"); |
或者直接获取指定方法:
1 | Class<?> clazz1 = Class.forName("com.qw.reflect.Student"); |
其中,getMethod的剩余参数表示获取方法所需要传参的类型。
接下来,重头戏,如何通过反射执行类中的方法呢:
1 | Class<?> clazz1 = Class.forName("com.qw.reflect.Student"); |
输出结果:
1 | 15年纪是年轻 |
需要注意的是,invoke方法的第一个参数是指定类的对象,因为isYoung
不是静态方法,必须要用指定的实体对象类执行。
至此,我们已经大致了解了java中反射的基本概念,知道了如何通过反射调用指定类中的方法了。
然而设计到注解的另一个问题是,我们并不想在反射处理器中实际执行方法,而仅仅是监视方法的执行,这就涉及到另一个概念:AOP。
SimpleDateFormat线程不安全验证实验
【强制】并发修改同一记录时,避免更新丢失, 需要加锁。 要么在应用层加锁,要么在缓存加
锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。
说明: 如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次
数不得小于 3 次。
【强制】多线程并行处理定时任务时, Timer 运行多个 TimeTask 时,只要其中之一没有捕获
抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。
这是我参与更文挑战的第19天,活动详情查看: 更文挑战
桃李不言,下自成蹊
前一段时间学习Go语言,了解到Go中的关键字go
可以开启协程goroutine
从而实现并发并行。其中有一个sync
包中的WaitGroup
可以实现异步转同步的功能:等待一组线程的结束。父协程调用Add
方法来设定等待的协程的数量,每个被等待的协程在结束任务执行时调用Done
方法;同时,父协程调用Wait
方法阻塞至所有线程结束。
例如,在另一篇文章:Go缓存击穿方案-singleflight源码解读,其中的singleflight就用waitGroup实现了其他协程需等待执行数据库请求的协程程执行完毕后才可获取到数据。如图中的:R2:call.wg.wait()
会等待 R1: call.done()
执行完后才执行后续代码。
问题来了,Java中异步转同步的方式又是如何呢?
CountDownLatch是Java的包java.util.concurrent
中的一个类,允许一个或多个线程等待其他线程完成操作后再执行,从而可以实现与Go中的WaitGroup
相同的效果。
Talk is Cheap, Show me the code!
1 | package multi.thread.xxxxx.com; |
执行结果:
1 | 子线程Thread-0正在执行 |
需要注意的是,子线程抛出异常堆栈,不能在主线程 try-catch 到。所以,子线程注意catch 异常,确保 countDown 方法被执行到,避免主线程无法执行至 await 方法,直到超时才返回结果。
入参保护
2018年10月读的H5的书籍,还没有读完