首页 文章 精选 留言 我的

精选列表

搜索[面试],共5092篇文章
优秀的个人博客,低调大师

java面试-深入理解JVM(五)——HotSpot垃圾收集器详解

HotSpot虚拟机提供了多种垃圾收集器,每种收集器都有各自的特点,没有最好的垃圾收集器,只有最适合的垃圾收集器。我们可以根据自己实际的应用需求选择最适合的垃圾收集器。 根据新生代和老年代各自的特点,我们应该分别为它们选择不同的收集器,以提升垃圾回收效率。 新生代垃圾收集器 1. Serial垃圾收集器 单线程只开启一条GC线程进行垃圾回收,并且在垃圾回收过程中停止一切用户线程,从而用户的请求或图形化界面会出现卡顿。 适合客户端应用一般客户端应用所需内存较小,不会创建太多的对象,而且堆内存不大,因此垃圾回收时间比较短,即使在这段时间停止一切用户线程,用户也不会感受到明显的停顿,因此本垃圾收集器适合客户端应用。 简单高效由于Serial收集器只有一条GC线程,因此避免了线程切换的开销,从而简单高效。 采用“复制”算法 2. ParNew垃圾收集器 ParNew是Serial的多线程版本。1. 多线程并行执行ParNew由多条GC线程并行地进行垃圾清理。但清理过程仍然需要停止一切用户线程。但由于有多条GC线程同时清理,清理速度比Serial有一定的提升。 适合多CPU的服务器环境由于使用了多线程,因此适合CPU较多的服务器环境。 与Serial性能对比ParNew和Serial唯一的区别就是使用了多线程进行垃圾回收,在多CPU的环境下性能比Serial会有一定程度的提升;但线程切换需要额外的开销,因此在单CPU环境中表现不如Serial。 采用“复制”算法 追求“降低停顿时间”和Serial相比,ParNew使用多线程的目的就是缩短垃圾收集时间,从而减少用户线程被停顿的时间。 3. Parallel Scavenge垃圾收集器 Parallel Scavenge和ParNew一样都是多线程、新生代收集器,都使用“复制”算法进行垃圾回收。但它们有个巨大的不同点:ParNew收集器追求降低用户线程的停顿时间,因此适合交互式应用;而Parallel Scavenge追求CPU吞吐量,能够在较短的时间内完成指定任务,因此适合没有交互的后台计算。 什么是“吞吐量”?吞吐量是指用户线程运行时间占CPU总时间的比例。CPU总时间包括:用户线程运行时间 和 GC线程运行的时间。因此,吞吐量越高表示用户线程运行时间越长,从而用户线程能够被快速处理完。 降低停顿时间的两种方式1.在多CPU环境中使用多条GC线程,从而垃圾回收的时间减少,从而用户线程停顿的时间也减少;2.实现GC线程与用户线程并发执行。所谓并发,就是用户线程与GC线程交替执行,从而每次停顿的时间会减少,用户感受到的停顿感降低,但线程之间不断切换意味着需要额外的开销,从而垃圾回收和用户线程的总时间将会延长。 Parallel Scavenge提供的参数 设置“吞吐量”通过参数-XX:GCTimeRadio设置垃圾回收时间占总CPU时间的百分比。 设置“停顿时间”通过参数-XX:MaxGCPauseMillis设置垃圾处理过程最久停顿时间。Parallel Scavenge会根据这个值的大小确定新生代的大小。如果这个值越小,新生代就会越小,从而收集器就能以较短的时间进行一次回收。但新生代变小后,回收的频率就会提高,因此要合理控制这个值。 启用自适应调节策略通过命令-XX:+UseAdaptiveSizePolicy就能开启自适应策略。我们只要设置好堆的大小和MaxGCPauseMillis或GCTimeRadio,收集器会自动调整新生代的大小、Eden和Survior的比例、对象进入老年代的年龄,以最大程度上接近我们设置的MaxGCPauseMillis或GCTimeRadio。 老年代垃圾收集器 1. Serial Old垃圾收集器 Serial Old收集器是Serial的老年代版本,它们都是单线程收集器,也就是垃圾收集时只启动一条GC线程,因此都适合客户端应用。 它们唯一的区别就是Serial Old工作在老年代,使用“标记-整理”算法;而Serial工作在新生代,使用“复制”算法。 2. Parallel Old垃圾收集器 Parallel Old收集器是Parallel Scavenge的老年代版本,一般它们搭配使用,追求CPU吞吐量。它们在垃圾收集时都是由多条GC线程并行执行,并停止一切用户线程。因此,由于在垃圾清理过程中没有使垃圾收集和用户线程并行执行,因此它们是追求吞吐量的垃圾收集器。 3. CMS垃圾收集器 CMS收集器是一款追求停顿时间的老年代收集器,它在垃圾收集时使得用户线程和GC线程并行执行,因此在垃圾收集过程中用户也不会感受到明显的卡顿。但用户线程和GC线程之间不停地切换会有额外的开销,因此垃圾回收总时间就会被延长。 垃圾回收过程 初始标记停止一切用户线程,仅使用一条初始标记线程对所有与GC ROOTS直接关联的对象进行标记。速度很快。 并发标记使用多条并发标记线程并行执行,并与用户线程并发执行。此过程进行可达性分析,标记出所有废弃的对象。速度很慢。 重新标记停止一切用户线程,并使用多条重新标记线程并行执行,将刚才并发标记过程中新出现的废弃对象标记出来。这个过程的运行时间介于初始标记和并发标记之间。 并发清除只使用一条并发清除线程,和用户线程们并发执行,清除刚才标记的对象。这个过程非常耗时。 CMS的缺点 吞吐量低由于CMS在垃圾收集过程使用用户线程和GC线程并行执行,从而线程切换会有额外开销,因此CPU吞吐量就不如在垃圾收集过程中停止一切用户线程的方式来的高。 无法处理浮动垃圾,导致频繁Full GC由于垃圾清除过程中,用户线程和GC线程并发执行,也就是用户线程仍在执行,那么在执行过程中会产生垃圾,这些垃圾称为“浮动垃圾”。如果CMS在垃圾清理过程中,用户线程需要在老年代中分配内存时发现空间不足时,就需要再次发起Full GC,而此时CMS正在进行清除工作,因此此时只能由Serial Old临时对老年代进行一次Full GC。 使用“标记-清除”算法产生碎片空间由于CMS使用了“标记-清除”算法, 因此清除之后会产生大量的碎片空间,不利于空间利用率。不过CMS提供了应对策略: 开启-XX:+UseCMSCompactAtFullCollection开启该参数后,每次FullGC完成后都会进行一次内存压缩整理,将零散在各处的对象整理到一块儿。但每次都整理效率不高,因此提供了以下参数。 设置参数-XX:CMSFullGCsBeforeCompaction本参数告诉CMS,经过了N次Full GC过后再进行一次内存整理。 通用垃圾收集器——G1垃圾收集器 G1是目前最牛逼的垃圾收集器。 G1的特点 追求停顿时间 多线程GC 面向服务端应用 标记-整理和复制算法合并不会产生碎片内存。 可对整个堆进行垃圾回收 可预测停顿时间 G1的内存模型 G1垃圾收集器没有新生代和老年代的概念了,而是将堆划分为一块块独立的Region。当要进行垃圾收集时,首先估计每个Region中的垃圾数量,每次都从垃圾回收价值最大的Region开始回收,因此可以获得最大的回收效率。 Remembered Set 一个对象和它内部所引用的对象可能不在同一个Region中,那么当垃圾回收时,是否需要扫描整个堆内存才能完整地进行一次可达性分析? 当然不是,每个Region都有一个Remembered Set,用于记录本区域中所有对象引用的对象所在的区域,从而在进行可达性分析时,只要在GC ROOTs中再加上Remembered Set即可防止对所有堆内存的遍历。 G1垃圾收集过程 初始标记标记与GC ROOTS直接关联的对象,停止所有用户线程,只启动一条初始标记线程,这个过程很快。 并发标记进行全面的可达性分析,开启一条并发标记线程与用户线程并行执行。这个过程比较长。 最终标记标记出并发标记过程中用户线程新产生的垃圾。停止所有用户线程,并使用多条最终标记线程并行执行。 筛选回收回收废弃的对象。此时也需要停止一切用户线程,并使用多条筛选回收线程并行执行。

优秀的个人博客,低调大师

java面试-深入理解JVM(二)——揭开HotSpot对象创建的奥秘

对象的创建过程 当虚拟机遇到一条含有new的指令时,会进行一系列对象创建的操作: 检查常量池中是否有即将要创建的这个对象所属的类的符号引用; 若常量池中没有这个类的符号引用,说明这个类还没有被定义!抛出ClassNotFoundException; 若常量池中有这个类的符号引用,则进行下一步工作; 进而检查这个符号引用所代表的类是否已经被JVM加载; 若该类还没有被加载,就找该类的class文件,并加载进方法区; 若该类已经被JVM加载,则准备为对象分配内存; 根据方法区中该类的信息确定该类所需的内存大小;一个对象所需的内存大小是在这个对象所属类被定义完就能确定的!且一个类所生产的所有对象的内存大小是一样的!JVM在一个类被加载进方法区的时候就知道该类生产的每一个对象所需要的内存大小。 从堆中划分一块对应大小的内存空间给新的对象;分配堆中内存有两种方式: 指针碰撞如果JVM的垃圾收集器采用复制算法或标记-整理算法,那么堆中空闲内存是完整的区域,并且空闲内存和已使用内存之间由一个指针标记。那么当为一个对象分配内存时,只需移动指针即可。因此,这种在完整空闲区域上通过移动指针来分配内存的方式就叫做“指针碰撞”。 空闲列表如果JVM的垃圾收集器采用标记-清除算法,那么堆中空闲区域和已使用区域交错,因此需要用一张“空闲列表”来记录堆中哪些区域是空闲区域,从而在创建对象的时候根据这张“空闲列表”找到空闲区域,并分配内存。综上所述:JVM究竟采用哪种内存分配方法,取决于它使用了何种垃圾收集器。 为对象中的成员变量赋上初始值(默认初始化); 设置对象头中的信息; 调用对象的构造函数进行初始化此时,整个对象的创建过程就完成了。 对象的内存模型 一个对象从逻辑角度看,它由成员变量和成员函数构成,从物理角度来看,对象是存储在堆中的一串二进制数,这串二进制数的组织结构如下。 对象在内存中分为三个部分: 对象头 实例数据 对齐补充 1. 对象头 对象头中记录了对象在运行过程中所需要使用的一些数据:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。 此外,对象头中可能还包含类型指针。通过该指针能确定这个对象所属哪个类。 此外,如果对象是一个数组,那么对象头中还要包含数组长度。 2. 实例数据 实力数据部分就是成员变量的值,其中包含父类的成员变量和本类的成员变量。 3. 对齐补充 用于确保对象的总长度为8字节的整数倍。HotSpot要求对象的总长度必须是8字节的整数倍。由于对象头一定是8字节的整数倍,但实例数据部分的长度是任意的,因此需要对齐补充字段确保整个对象的总长度为8的整数倍。 访问对象的过程 我们知道,引用类型的变量中存放的是一个地址,那么根据地址类型的不同,对象有不同的访问方式: 句柄访问方式堆中需要有一块叫做“句柄池”的内存空间,用于存放所有对象的地址和所有对象所属类的类信息。引用类型的变量存放的是该对象在句柄池中的地址。访问对象时,首先需要通过引用类型的变量找到该对象的句柄,然后根据句柄中对象的地址再访问对象。 直接指针访问方式引用类型的变量直接存放对象的地址,从而不需要句柄池,通过引用能够直接访问对象。但对象所在的内存空间中需要额外的策略存储对象所属的类信息的地址。 比较 HotSpot采用直接指针方式访问对象,因为它只需一次寻址操作,从而性能比句柄访问方式快一倍。但它需要额外的策略存储对象在方法区中类信息的地址。

优秀的个人博客,低调大师

java面试-Java并发编程(九)——批量获取多条线程的执行结果

当向线程池提交callable任务后,我们可能需要一次性获取所有返回结果,有三种处理方法。 方法一:自己维护返回结果 // 创建一个线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); // 存储执行结果的List List<Future<String>> results = new ArrayList<Future<String>>(); // 提交10个任务 for ( int i=0; i<10; i++ ) { Future<String> result = executorService.submit( new Callable<String>(){ public String call(){ int sleepTime = new Random().nextInt(1000); Thread.sleep(sleepTime); return "线程"+i+"睡了"+sleepTime+"秒"; } } ); // 将执行结果存入results中 results.add( result ); } // 获取10个任务的返回结果 for ( int i=0; i<10; i++ ) { // 获取包含返回结果的future对象 Future<String> future = results.get(i); // 从future中取出执行结果(若尚未返回结果,则get方法被阻塞,直到结果被返回为止) String result = future.get(); System.out.println(result); } 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 此方法的弊端: 需要自己创建容器维护所有的返回结果,比较麻烦; 从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。 方法二:使用ExecutorService的invokeAll函数 本方法能解决第一个弊端,即并不需要自己去维护一个存储返回结果的容器。当我们需要获取线程池所有的返回结果时,只需调用invokeAll函数即可。但是,这种方式需要你自己去维护一个用于存储任务的容器。 // 创建一个线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建存储任务的容器 List<Callable<String>> tasks = new ArrayList<Callable<String>>(); // 提交10个任务 for ( int i=0; i<10; i++ ) { Callable<String> task = new Callable<String>(){ public String call(){ int sleepTime = new Random().nextInt(1000); Thread.sleep(sleepTime); return "线程"+i+"睡了"+sleepTime+"秒"; } }; executorService.submit( task ); // 将task添加进任务队列 tasks.add( task ); } // 获取10个任务的返回结果 List<Future<String>> results = executorService.invokeAll( tasks ); // 输出结果 for ( int i=0; i<10; i++ ) { // 获取包含返回结果的future对象 Future<String> future = results.get(i); // 从future中取出执行结果(若尚未返回结果,则get方法被阻塞,直到结果被返回为止) String result = future.get(); System.out.println(result); } 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 方法三:使用CompletionService CompletionService内部维护了一个阻塞队列,只有执行完成的任务结果才会被放入该队列,这样就确保执行时间较短的任务率先被存入阻塞队列中。 ExecutorService exec = Executors.newFixedThreadPool(10); final BlockingQueue<Future<Integer>> queue = new LinkedBlockingDeque<Future<Integer>>( 10); //实例化CompletionService final CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>( exec, queue); // 提交10个任务 for ( int i=0; i<10; i++ ) { executorService.submit( new Callable<String>(){ public String call(){ int sleepTime = new Random().nextInt(1000); Thread.sleep(sleepTime); return "线程"+i+"睡了"+sleepTime+"秒"; } } ); } // 输出结果 for ( int i=0; i<10; i++ ) { // 获取包含返回结果的future对象(若整个阻塞队列中还没有一条线程返回结果,那么调用take将会被阻塞,当然你可以调用poll,不会被阻塞,若没有结果会返回null,poll和take返回正确的结果后会将该结果从队列中删除) Future<String> future = completionService.take(); // 从future中取出执行结果,这里存储的future已经拥有执行结果,get不会被阻塞 String result = future.get(); System.out.println(result); }

优秀的个人博客,低调大师

java面试-Java并发编程(八)——闭锁、同步屏障、信号量详解

1. 闭锁:CountDownLatch 1.1 使用场景 若有多条线程,其中一条线程需要等到其他所有线程准备完所需的资源后才能运行,这样的情况可以使用闭锁。 1.2 代码实现 // 初始化闭锁,并设置资源个数 CountDownLatch latch = new CountDownLatch(2); Thread t1 = new Thread( new Runnable(){ public void run(){ // 加载资源1 加载资源的代码…… // 本资源加载完后,闭锁-1 latch.countDown(); } } ).start(); Thread t2 = new Thread( new Runnable(){ public void run(){ // 加载资源2 资源加载代码…… // 本资源加载完后,闭锁-1 latch.countDown(); } } ).start(); Thread t3 = new Thread( new Runnable(){ public void run(){ // 本线程必须等待所有资源加载完后才能执行 latch.await(); // 当闭锁数量为0时,await返回,执行接下来的任务 任务代码…… } } ).start(); 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 2. 同步屏障:CyclicBarrier 2.1 使用场景 若有多条线程,他们到达屏障时将会被阻塞,只有当所有线程都到达屏障时才能打开屏障,所有线程同时执行,若有这样的需求可以使用同步屏障。此外,当屏障打开的同时还能指定执行的任务。 2.2 闭锁 与 同步屏障 的区别 闭锁只会阻塞一条线程,目的是为了让该条任务线程满足条件后执行; 而同步屏障会阻塞所有线程,目的是为了让所有线程同时执行(实际上并不会同时执行,而是尽量把线程启动的时间间隔降为最少)。 2.3 代码实现 // 创建同步屏障对象,并制定需要等待的线程个数 和 打开屏障时需要执行的任务 CyclicBarrier barrier = new CyclicBarrier(3,new Runnable(){ public void run(){ //当所有线程准备完毕后触发此任务 } }); // 启动三条线程 for( int i=0; i<3; i++ ){ new Thread( new Runnable(){ public void run(){ // 等待,(每执行一次barrier.await,同步屏障数量-1,直到为0时,打开屏障) barrier.await(); // 任务 任务代码…… } } ).start(); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 3. 信号量:Semaphore 3.1 使用场景 若有m个资源,但有n条线程(n>m),因此同一时刻只能允许m条线程访问资源,此时可以使用Semaphore控制访问该资源的线程数量。 3.2 代码实现 // 创建信号量对象,并给予3个资源 Semaphore semaphore = new Semaphore(3); // 开启10条线程 for ( int i=0; i<10; i++ ) { new Thread( new Runnbale(){ public void run(){ // 获取资源,若此时资源被用光,则阻塞,直到有线程归还资源 semaphore.acquire(); // 任务代码 …… // 释放资源 semaphore.release(); } } ).start(); }

优秀的个人博客,低调大师

Java动态代理机制——那些让你面试脱颖而出的技能

retrofit是一个解耦性非常高的网络请求框架,最近在研究的时候发现了动态代理这个非常强大且实用的技术,这篇文章将作为retrofit的前置知识,让大家认识:动态代理有哪些应用场景,什么是动态代理,怎样使用,它的局限性在什么地方?#动态代理的应用场景 1. AOP—面向切面编程,程序解耦简言之当你想要对一些类的内部的一些方法,在执行前和执行后做一些共同的的操作,而在方法中执行个性化操作的时候--用动态代理。在业务量庞大的时候能够降低代码量,增强可维护性。 2. 想要自定义第三放类库中的某些方法我引用了一个第三方类库,但他的一些方法不满足我的需求,我想自己重写一下那几个方法,或在方法前后加一些特殊的操作--用动态代理。但需要注意的是,这些方法有局限性,我会在稍后说明。 什么是动态代理 以上的图太过于抽象,我们从生活中的例子开始切入。 假如你是一个大房东(被代理人),你有很多套房子想要出租,而你觉得找租客太麻烦,不愿意自己弄,因而你找一个人来代理你(代理人),帮打理这些东西,而这个人(代理人也就是中介)在帮你出租房屋的时候对你收取一些相应的中介费(对房屋出租的一些额外操作)。对于租客而言,中介就是房东,代理你做一些事情。 以上,就是一个代理的例子,而他为什么叫动态代理,“动态”两个字体现在什么地方? 我们可以这样想,如果你的每一套房子你都请一个代理人帮你打理,每当你想再出租一套房子的时候你得再请一个,这样你会请很多的代理人,花费高额的中介成本,这可以看作常说的“静态代理”。 但假如我们把所有的房子都交给一个中介来代理,让他在多套房子之间动态的切换身份,帮你应付每一个租客。这就是一个“动态代理”的过程。动态代理的一大特点就是编译阶段没有代理类在运行时才生成代理类。 我们用一段代码来看一下 房屋出租的操作 /** *定义一个借口 **/ public interface RentHouse { void rent();//房屋出租 void charge(String str);//出租费用收取 } 房东 public class HouseOwner implements RentHouse { public void rent() { System.out.println("I want to rent my house"); } public void charge(String str) { System.out.println("You get : " + str + " RMB HouseCharge."); } } 中介 public class DynamicProxy implements InvocationHandler { // 这个就是我们要代理的真实对象,即房东 private Object subject; // 构造方法,给我们要代理的真实对象赋初值 public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作,中介收取中介费 System.out.println("before "+method.getName()+" house"); System.out.println("Method:" + method.getName()); // 如果方法是 charge 则中介收取100元中介费 if (method.getName().equals("charge")) { method.invoke(subject, args); System.out.println("I will get 100 RMB ProxyCharge."); } else { // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); } // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("after "+method.getName()+" house"); return null; } 客人 public class Client { public static void main(String[] args) { // 我们要代理的真实对象--房东 HouseOwner houseOwner = new HouseOwner(); // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new DynamicProxy(houseOwner); /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner .getClass().getInterfaces(), handler);//一个动态代理类,中介 System.out.println(rentHouse.getClass().getName()); rentHouse.rent(); rentHouse.charge("10000"); } } 我们来看一下输出 com.sun.proxy.$Proxy0 before rent house Method:rent I want to rent my house after rent house before charge house Method:charge You get : 10000 RMB HouseCharge. I will get 100 RMB ProxyCharge. after charge house Process finished with exit code 0 输出里有 before rent house以及after rent house,说明我们可以在方法的前后增加操作。再看输出 I will get 100 RMB ProxyCharge. 中介收取了100块的中介费,说明我们不仅可以增加操作,甚至可以替换该方法或者直接让该方法不执行。 刚开始看代码你可能会有很多疑惑,我们通过以下的内容来看看动态代理应该怎么用。 #动态代理该如何使用在java的动态代理机制中,有两个重要的类和接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。 每一个动态代理类都必须要实现InvocationHandler这个接口(代码中的中介),并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke(对方法的增强就写在这里面) 方法来进行调用。 Object invoke(Object proxy, Method method, Object[] args) throws Throwable 我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢? Object invoke(Object proxy, Method method, Object[] args) throws Throwable //proxy: 指代我们所代理的那个真实对象 //method: 指代的是我们所要调用真实对象的某个方法的Method对象 //args: 指代的是调用真实对象某个方法时接受的参数 接下来我们来看看Proxy这个类 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException //loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 //interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 //h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上 这样一来,结合上面给出的代码,我们就可以明白动态代理的使用方法了 #动态代理的局限性从动态代理的使用方法中我们看到其实可以被增强的方法都是实现了借口的(不实现借口的public方法也可以通过继承被代理类来使用),代码中的HouseOwner继承了RentHouse 。而对于private方法JDK的动态代理无能为力!以上的动态代理是JDK的,对于java工程还有大名鼎鼎的CGLib,但遗憾的是CGLib并不能在android中使用,android虚拟机相对与jvm还是有区别的。 结束语 动态代理的使用场景远不止这些,内部原理会在以后的文章中介绍,但应用类反射临时生成代理类这一机制决定它对性能会有一定的影响。本文作为retrofit原理的前置文章并没有太过详尽,如有疏漏和错误,欢迎指正!

优秀的个人博客,低调大师

WF4.0实战(十三):解微软一道面试题

题目:一个整数数列,元素取值可能是0—65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。 请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。 注意: 1、5个数值允许是乱序的。比如: 8 7 5 0 6; 2、0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4; 3、0可以多次出现; 4、复杂度如果是O(n2)则不得分。 分析:通过分析你可以发现,题目只要满足:除0之外的最大数减去除0之外的最小数小于等于4就行了。 故只要通过一个循环就5个数字中除0之外的最大数和最小数。求差之后与4做个比较就行了。伪代码如下: 1 public booleanisContiguous( int []array) 2 { 3 int min =- 1 ; 4 int max =- 1 ; 5 for ( int i = 0 ;i < array.length;i ++ ) 6 { 7 if (array[i] != 0 ) 8 { 9 if (min ==- 1 || min > array[i]) 10 { 11 min = array[i]; 12 } 13 if (max ==- 1 || max < array[i]) 14 { 15 max = array[i]; 16 } 17 } 18 } 19 return max - min <= array.length - 1 ; 20 } 下面让我用WF4.0来实现解这个题目,思路和上面代码思想是一致的。 流程: 实现: 1、产生随机数流程GenerateRandom流程,如下图: 2、验证产生的数字是否满足条件: 3、输出结果: 4、整个流程: 运行结果: 0~65535范围太大,很难产生出5位连续的数字,将范围缩小为1-6: 总结:这篇文章主要说明使用WF4.0和你写一般的C#代码一样,复杂的逻辑它也可以实现。一些复杂的算法可能会因为它的可视化编程而变得更简单。 本文转自麒麟博客园博客,原文链接:http://www.cnblogs.com/zhuqil/archive/2010/05/07/msInterview.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Linux云计算岗位面试时最常遇到的40个问题

1)使用云计算有哪些优点? 使用云计算有下列优点: a)备份数据和存储数据 b)强大的服务器功能 c)SaaS(软件即服务) d)信息技术沙盒功能 e)提高生产力 f)具有成本效益,并节省时间 2)可否列举哪些平台用于大规模云计算? 用于大规模云计算的平台包括: a)Apache Hadoop b)MapReduce 3)可否解释用于云计算部署的不同模式? 不同的云计算部署模式包括: a)私有云 b)公共云 c)社区云 d)混合云 4)云计算与移动计算有何区别? 移动计算使用与云计算同样的概念。借助互联网而不是借助单个设备,云计算因数据而变得活跃。它为用户提供了需要按需获取的数据。在移动计算中,应用程序在远程服务器上运行,为用户提供了访问所存储数据的权限。 5)用户如何得益于公用计算(utility computing)? 公用计算让用户可以只需要为使用的资源付费。它是由决定从云端部署哪种类型的服务的企业组织管理的一种插件。 大多数企业组织青睐混合策略。 6)由于数据在云端传输,你如何确保数据安全? 数据从一个地方传输到另一地方的过程中想确保数据安全,就要确保针对你发送的数据所使用的加密密钥没有泄露。 7)云在安全方面的措施有哪些? a)身份管理:授权应用程序服务。 b)访问控制:将权限授予用户,那样用户可以控制进入到云环境的另一个用户的访问。 c)验证和授权:只允许通过授权和验证的用户访问数据和应用程序。 8)可否列出定义云架构的不同层? 8)云架构使用的不同层包括: a)CLC即云控制器 b)Walrus c)集群控制器 d)SC即存储控制器 e)NC即节点控制器 9)云计算系统集成商的角色是什么? 在云计算中,系统集成商负责为用来设计云平台的复杂过程制定策略。集成商需要构建更准确的混合云和私有云网络,因为集成商拥有数据中心构建方面的全部知识。 10)“EUCALYPTUS”的全称是什么? “EUCALYPTUS”的全称是将你的程序连接到实用系统的弹性公用计算架构。 11)可否解释“EUCALYPTUS”在云计算中有何用处? Eucalyptus是云计算中的一种开源软件基础设施,它用来将集群实施到云计算平台上。它用来构建公共云、混合云和私有云。它能够将你自己的数据中心打造成私有云,并让你可以将其功能应用于其他许多企业组织。 12)虚拟化平台在实施云时有何要求? 虚拟化平台在实施云时的要求包括: a)管理服务级别策略 b)云操作系统 c)虚拟化平台有助于让后端级别概念和用户级别概念彼此不同。 13)在使用云计算平台前,用户需要考虑哪些必要的方面? a)合规 b)数据丢失 c)数据存储 d)业务连续性 e)正常运行时间 f)云计算的数据完整性 14)可否列举几个开源云计算平台数据库? 开源云计算平台数据库有: a)MongoDB b)CouchDB c)LucidDB 15)落实了哪些安全法规来保护云端数据的安全? 为保护云端数据安全而落实的安全法规包括: a)处理:控制在应用程序中正确、完整处理的数据。 b)文件:它管理和控制任何文件中处理的数据。 c)输出调和:它控制输入和输出之间需要调和的数据。 d)输入验证:控制输入数据。 e)安全和备份:它提供安全和备份,还控制安全泄密日志。 16)可否列举几个大型云提供商的数据库名称? a)Google bigtable b)Amazon simpleDB c)基于云的SQL 17)可否解释云与传统数据中心之间的区别? a)由于供暖和硬件/软件问题,传统数据中心的成本比较高。 b)需求增加时,云可以扩增资源。大部分开支花在了数据中心的维护上,而云计算不是这样。 18)可否解释软件即服务(SaaS)的不同模式? a)简单的多租户模式:在该模式中,每个用户有独立的资源,与其他用户分开来,这是一种高效的模式。 b)细粒度的多租户模式:在这种模式中,资源由许多租户共享,但是功能仍然一样。 19)API在云服务中有何用途? API(应用编程接口)在云平台中非常有用 a)不需要编写功能完备的程序。 b)提供了在一个或多个应用程序之间进行联系的指令。 c)易于构建应用程序,并将云服务与其他系统联系起来。 20)为云计算部署了哪些不同的数据中心? 云计算包括不同的数据中心,比如 a)容器化数据中心 b)低密度数据中心 21)云计算中有哪些不同的层? 云计算的不同层包括: a)SaaS:软件即服务,它让用户可以直接访问云应用程序,不必在系统上安装任何东西。 b)IaaS:基础设施即服务,它从硬件(比如内存和处理器速度等)等层面提供了基础设施。 c)PaaS:平台即服务,它为开发人员提供了云应用程序平台。 22)平台即服务有多重要? 平台即服务(PAAS)是云计算中一个很重要的层。它为提供商提供了应用程序平台。它负责提供基础设施层的全面虚拟化,让它运行起来如同单一的服务器。 23)云服务是什么? 云服务用来通过互联网,使用网络中的服务器来构建云应用程序。它提供了这种便利:不必将云应用程序安装到计算机上,即可直接使用。它还减少了维护和支持使用云服务开发的应用程序的工作。 24)可否列出云计算领域的三种基本云? A)专业云 B)私人云 C)高性能云 25)就基础设施即服务而言,它提供了什么资源? IAAS(基础设施即服务)提供了用来构建云的虚拟资源和物理资源。它负责处理部署和维护这一层提供的服务带来的复杂性。在这里,基础设施是服务器、存储系统及其他硬件系统。 26)云架构有什么样的业务好处? 云架构具有的好处包括: a)无需基础设施投入 b)适时的基础设施 c)更高效地利用资源 27)云架构有别于传统架构的特点有哪些? 让云架构有别于传统架构的特点包括: a)按照需求,云架构满足硬件要求。 b)云架构能够按需增减资源。 c)云架构能够管理和处理动态工作负载,顺畅无阻。 28)可否列举云计算中弹性与可扩展性的区别? 可扩展性是云计算的一个特点;借助可扩展性,只要相应增加资源容量,就可以处理增加的工作负载。作为云计算的另一个特点,弹性强调了启用和停用庞大的资源容量这一概念。 29)可否列举由Window Azure操作系统提供的服务? Window Azure提供了三种核心服务,包括: a)计算服务 b)存储服务 c)管理服务 30)在云架构中,必需的不同部分有哪些? a)云入站 b)处理器速度 c)云存储服务 d)云提供商服务 e)云间通信 31)在云架构中,经历的不同阶段有哪些? a)启动阶段 b)监测阶段 c)关闭阶段 d)清理阶段 32)可否列出云计算的基本特点? a)弹性和可扩展性 b)自助式配置和自动取消配置 c)标准化界面 d)自助计费的使用模式 33)在云架构中,基本的构建模块有哪些? a)参考架构 b)技术架构 c)部署操作架构 34)可否描述云架构以哪些方式来提供自动化和性能透明度? 为了提供性能透明度和自动化,云架构使用许多工具。它可以管理云架构和监测报告。它还可以共享使用云架构的应用程序。自动化是云架构的关键部分,有助于改善质量级别。 35)可否解释一下高性能云在云计算中的角色? 高性能云在立即传输最大数量的数据方面很有用。从事高性能计算研究的专业人员经常使用高性能云。 36)可否解释混合云和社区云? 混合云:混合云包括多家服务提供商。它结合了公共云和私有云的功能。公司同时需要私有云和公共云时,就会使用混合云。 社区云:这种模式的成本相当高;多家企业组织有着共同的目标和需求,又准备共享云服务的优点时,就会使用社区云。 37)在云中,优化策略有哪些? 为了克服维护成本,并且优化资源,用到云端三个数据中心这个概念:提供恢复和备份机制,万一出现灾难或系统故障,可确保所有数据安全无恙。 38)亚马逊SQS是什么东东? 为了在不同的连接件之间联系,就要使用亚马逊SQS消息;它在亚马逊的不同组件中充当“联络者”。 39)缓冲器如何用于亚马逊网络服务? 为了让系统更高效地应对流量或负载突增的情况,提供商使用缓冲器。缓冲器可同步不同的组件。组件始终以一种不平衡的方式接收和处理请求。不同组件之间的平衡由缓冲器来负责管理,好让它们以同样的速度来工作,从而提供更快的服务。 40)可否描述云计算中的虚拟机管理程序及其类型? 虚拟机管理程序是虚拟机监测工具,为虚拟机管理资源。虚拟机管理程序主要有两种类型。 类型1:访客虚拟机直接在主机硬件上运行,比如Xen和VMWare ESXI。 类型2:访客虚拟机通过主机操作系统在硬件上运行,比如KVM和OracleVirtualBox。 作者:运维派 来源:http://www.yunweipai.com/archives/18460.html 本文转自 ChinaUnicom110 51CTO博客,原文链接: http://blog.51cto.com/xingyue2011/1959411

优秀的个人博客,低调大师

Android面试,简要介绍一下asynctask和handler的优缺点

1 )AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程. 使用的优点: l 简单,快捷 l 过程可控 使用的缺点: l 在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来. l 最大并发数不超过5 2 )Handler异步实现的原理和适用的优缺点 在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程),thread(子线程)运行并生成Message,Looper获取Message并传递给Handler,Handler逐个获取Looper中的Message,并进行UI变更。 使用的优点: l 结构清晰,功能定义明确 l 对于多个后台任务时,简单,清晰 使用的缺点: l 在单个后台异步处理时,显得代码过多,结构过于复杂(相对性) AsyncTask介绍 Android的AsyncTask比Handler更轻量级一些,适用于简单的异步处理。 首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。 Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。 AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。 AsyncTask定义了三种泛型类型 Params,Progress和Result。 Params 启动任务执行的输入参数,比如HTTP请求的URL。 Progress 后台任务执行的百分比。 Result 后台执行任务最终返回的结果,比如String。 使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法: doInBackground(Params…)后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。 onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回 有必要的话你还得重写以下这三个方法,但不是必须的: onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。 onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。 onCancelled() 用户调用取消时,要做的操作 使用AsyncTask类,以下是几条必须遵守的准则: Task的实例必须在UI thread中创建; execute方法必须在UI thread中调用; 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法; 该task只能被执行一次,否则多次调用时将会出现异常; 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3909603.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

WorkBuddy 与 Skill 联动:搭建远程面试 / 线上考试身份核验全链路

腾讯云把官网的 AI 能力封装成标准 Skill,开放给 WorkBuddy CodeBuddy ADP 这类智能体平台做二次开发。这次征集把「安全风控」列为了重点方向——而远程身份核验恰好是这条线上最该被拎出来讲的场景:镜头前到底是不是本人、是不是真人、有没有被 AIGC 换脸,每个问题都对应一个现成的 Skill,天然适合串成一条完整链路。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册