参考:web缓存的了解
参考:Java检查异常、非检查异常、运行时异常、非运行时异常的区别
参考:finally代码块中的代码一定会执行吗?
首先我们需要了解java程序运行的过程,该过程包含两个阶段编译期和运行期。首先java代码会通过jdk编译成.class字节码文件,程序运行的时候,jvm会去调用业务逻辑对应需要的的字节码文件,生成对应的Class对象,并调用其中的属性方法完成业务逻辑。
而java反射则是在运行期时,主动让jvm去加载某个.class文件生成Class对象,并调用其中的方法属性。
Class.forName这个方法比较耗时,它实际上调用了一个本地方法,通过这个方法来要求JVM查找并加载指定的类。
利用缓存
可以把Class.forName返回的Class对象缓存起来,下一次使用的时候直接从缓存里面获取,这样就极大的提高了获取Class的效率。同理,在我们获取Constructor、Method等对象的时候也可以缓存起来使用,避免每次使用时再来耗费时间创建。
通过字节码生成的方式来实现的反射机制
高性能反射工具包ReflectASM:reflectasm
Java事件机制包括三个部分:事件、事件监听器、事件源,使用的设计模式是监听者模式
这边 写了一个开门的事件监听,可以帮助理解这个东西
事件,一般是继承了EventObject
事件就是作为事件监听器触发的依据
/**
* 事件,一般是继承了EventObject
* 事件就是作为事件监听器触发的依据
*/
class DoorEvent extends EventObject {
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @exception IllegalArgumentException if source is null.
*/
public DoorEvent(Object source,String control) {
super(source);
this.control = control;
}
private String control;
public String getControl() {
return control;
}
public void setControl(String control) {
this.control = control;
}
public void open() {
System.out.println("open the door");
}
public void close() {
System.out.println("close the door");
}
}
获取到对应的事件,进行事件监听,根据不同的事件作出不同的反馈
一般一类事件监听器对应一类事件
interface DoorEventListener extends EventListener {
void doorControl(DoorEvent doorEvent);
}
class DoorListenerImpl implements DoorEventListener {
@Override
public void doorControl(DoorEvent doorEvent) {
if ("open".equals(doorEvent.getControl())) {
doorEvent.open();
} else if ("close".equals(doorEvent.getControl())) {
doorEvent.close();
}
}
}
事件源,可以理解为事件发生的地方
有一组时间监听器,当发生一个对应的事情的时候,通知对应的事件监听器去处理对应的事件
class DoorEventSource {
private List<DoorEventListener> doorEventListener;
public List<DoorEventListener> getDoorEventListener() {
return doorEventListener;
}
public void setDoorEventListener(List<DoorEventListener> doorEventListener) {
this.doorEventListener = doorEventListener;
}
public void openDoor(){
System.out.println("我要进门了");
doorEventListener.forEach(item->item.doorControl(new DoorEvent(this,"open")));
}
public void closeDoor(){
System.out.println("我要出门了");
doorEventListener.forEach(item->item.doorControl(new DoorEvent(this,"close")));
}
}
进行事件的触发
public static void main(String[] args) {
DoorEventSource doorEventSource = new DoorEventSource();
doorEventSource.setDoorEventListener(Lists.newArrayList(new DoorListenerImpl()));
doorEventSource.openDoor();
doorEventSource.closeDoor();
}
Spring的ApplicationEvent也是去继承了EventObject,再往下也有很多的具体事件实现类去区分不同的事件。
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened */
private final long timestamp;
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
Spring的事件监听器继承Eventlistener,同样对于不同的事件,有不同的事件监听的实现。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
当Spring进行onRefresh调用的时候会去触发事件的发布。
1.首先是注册监听器,往事件发布者(事件源)中注册对应的监听器
注释提取
创建一个执行器,该执行器使用单个工作线程在无边界队列上操作。
只创建一个执行器,不设置超时.也就是说永远只有一个执行器在执行。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
注释提取
在任何时候,最多n个线程将是活动的处理任务。如果在所有线程都处于活动状态时提交了其他任务,则它们将在队列中等待线程可用。
不设置超时时间,corePoolSize和MaxPoolSize一样,也就是说任何时间都只有一定量的线程在执行。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
注释提取
这些池通常会提高执行许多短期异步任务的程序的性能。执行调用将重用先前构造的线程(如果可用)。如果没有现有线程可用,将创建一个新线程并将其添加到池中。已60秒未使用的线程将被终止并从缓存中移除。
使用无界限队列SynchronousQueue,设置60S超时时间,corePoolSize容量为0。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
定时任务线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
参考:介绍 ForkJoinPool 的适用场景,实现原理
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
Web缓存就在服务器-客户端之间搞监控,监控请求,并且把请求输出的内容(例如html页面、 图片和文件)(统称为副本)另存一份;然后,如果下一个请求是相同的URL,则直接请求保存的副本,而不是再次麻烦源服务器。
降低延迟
缓存离客户端更近,因此,从缓存请求内容比从源服务器所用时间更少,呈现速度更快,网站就显得更灵敏。
降低网络传输
副本被重复使用,大大降低了用户的带宽使用,其实也是一种变相的省钱(如果流量要付费的话),同时保证了带宽请求在一个低水平上,更容易维护了。
1. 浏览器缓存
浏览器会在你的硬盘上专门开辟一个空间专门为你存储资源副本。浏览器缓存的工作规则很简单:检查以确保副本是最新的,通常只要一次会话(就是当前浏览器调用的这次N)。
浏览器缓存在用户触发“后退”操作或点击一个之前看过的链接的时候很管用。同样,如果你在网站上访问同一张图片,该图片可以从浏览器缓存中调出并几乎立即显现出来。
2.代理服务器缓存
用户设定浏览器通过缓存进行Web访问
浏览器向缓存/代理服务器发送所有的HTTP请求
如果所请求的对象在缓存中,缓存返回对象
否则,缓存服务器向原始的服务器发送HTTP请求,
获取对象,然后返回给客户端并保存该对象。
3. 网关缓存
也被称为“反向代理缓存”或“替代缓存”。网关缓存同样是起中介作用的,不过不是(素不相识、不曾谋面的Add)网络管理员部署的,而多半是网站管理员(公司专门的运维工程师、或UED或程序组某人Add)他们自己部署,这样更容易扩展与维护。cdn 和负载均衡就是这个应用。
当需要改动远端服务器的数据的时候,更新变化的那部分的数据,并且要设置一个新的Last-Modified值。
而客户端从缓存服务器获取数据的时候,先会拿着Last-Modified 的值和远端服务器做对比,如果发生改变则获取最新的资源进行缓存,如果没有改变,则直接返回缓存服务器当前的缓存即可。
参考:白话解析:一致性哈希算法
防丢失:截图保存
就是编译器要求你必须处理的异常。比如我们在编程某个文件的读于写时,编译器要求你必须要对某段代码try…catch… 或者 throws exception,这就是检查异常,简单的来说,你代码还没有运行,编码器就会检查你的代码,对可能出现的异常必须做出相对的处理。(比如当文件不存在时…)
编译器不要求强制处置的异常,虽然有可能出现错误,但是我不会在编译的时候检查。
答案:不一定,我们来看一下几种场景
public static boolean getTrue(boolean flag) {
if (flag) {
return flag;
}
try {
flag = true;
return flag;
} finally {
System.out.println("我是一定会执行的代码?");
}
}
public static boolean getTrue(boolean flag) {
int i = 1/0;
try {
flag = true;
return flag;
} finally {
System.out.println("我是一定会执行的代码?");
}
}
public static boolean getTrue(boolean flag) {
try {
flag = true;
System.exit(1);
return flag;
} finally {
System.out.println("我是一定会执行的代码?");
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5);
} catch (Exception e) {
}finally{
System.out.println("我是一定会执行的代码?");
}
}
});
t1.setDaemon(true);//设置t1为后台线程
t1.start();
System.out.println("我是主线程中的代码,主线程是非后台线程。");
}
如果finally中执行报错,报错之后的内容不会再执行。如果在finally中返回,则不会返回
public static void main(String[] args) {
int i = get();
System.out.println(i);
}
private static int get() {
try{
System.out.println("try");
}finally {
int i = 1/0;
System.out.println("catch");
return 1;
}
}