在异常处理上也不一样,在任务抛出异常时,如果是通过execute()提交的,会抛出无需捕获的异常(如果你没有特殊处理,会打印错误栈道System.err)。如果是通过submit()提交的,任何异常,无论是不是checked exception,都是返回的一部分,Future.get将把异常包在ExecutionExeption中,向上层抛出。
如果你想学习任何Future, Callable,异步计算和提高并发编程技巧,建议你学习这个课程Java Concurrency Practice in Bundle.
这是一个基于Brian Goetz独立编写的并发编程实践 的高级课程。这个课程绝对对得起你付出的钱和时间。并发编程很难而且有很多技巧,书和课程结合起来一起学是不错的方式。
问题8: 工厂模式和抽象工厂模式有什么区别?(答案)答:抽象工场模式提供一个多层级的抽象。考虑不同的工厂继承自同一个抽象工厂,代表基于工厂的不同对象结构的创建,例如,AutomobileFactory,UserFactory, RoleFactory等都继承自AbstractFactory。每一个独立的工厂代表那种类型物体的创造器。
如果你想要学习更多关于抽象工厂设计模式,我建议你看Java设计模式 这个课程,提供了优秀的真实案例帮你更好的理解设计模式。
这里是一个工厂模式和抽象工厂模式的UML图:
如果你想要更多选择,也可以看这个课程:5个设计模式
问题9: 什么是单例?整个方法使用synchronized和只有临界区使用synchronized哪个好?(答案)答:Java中的单例是指在整个Java应用中一个类只有一个实例。例如, java.lang.Runtime是一个单例类。
创建一个单例在Java 4之前非常难,但是自从Java 5 引入了枚举:enum, 它变得非常容易了。
你可以看我的这篇文章如何在Java中创建线程安全的单例,这里使用了枚举和双重校验锁的方式,这个题主要就是想问这个。
问题10: 你能基于Java 4,Java5里面的HashMap如何迭代取值?这个问题有点棘手,但是一般是使用while或者for循环。Java里面迭代Map有四种方式。一种是使用keySet(),迭代每一个key的时候使用get()方法去取value,但是有点慢。第二种方法是使用entrySet()。然后使用for each循环或者Iterator.hashNext()方法来迭代取值即可。 (keySet, entrySet和foreach, Iterator进行组合,所以是4种。)
这个方法比较好,因为在每次迭代时,key 和 value 都已经取出来了,你不需要调用get()方法去取value,使用get()方法当你从一个桶里面的大的链表中取数据,时间复杂度是O(n)。
你可以在我的博客4种方法迭代Java Map 中查看细节和示例代码。
问题11:什么时候重写 hashCode() 和 equals() 方法?(答案)答:当你需要的时候,尤其是你想要通过业务逻辑校验两个对象是否相等,而不是通过两个对象是否执行同一地址。例如两个员工对象在emp_id 相等的时候相等,即使它们是通过不同的代码创建出来的两个不同对象。
另外,如果你使用一个对象作为HashMap的key,你必须重写这两个方法。
作为java equals-hashcode约束的一部分,你当你重写equals的时候,你必须重写hashcode. 否则你不能再Set,Map这样的类里面使用,因为他们一来于equals()方法来保证逻辑正确性。
你也可以看我的这篇文章看理解重写这两个方法可能导致的问题: java equals中的5个技巧
问题12:在重写hashCode()方法的时候你遇到哪些问题?如果你不重写equals方法,equals和hashcode中的约束不会生效。根据该约束,两个对象通过equals()相等,一定有相同的hashcode。
在这种情况下,另一个对象可能返回一个不同的hashCode并存储在该位置,将破坏HashMap类的不可变,因为它不支持重复的key。
当你使用put()方法添加对象时,它迭代之前在map中那个桶位置的所有的Map.Entry对象,并且更新到新值。如果Map已经包含了那个Key,如果hashCode没有重写,这个机制不会起作用。
如果你想要学习更多关于Java集合(Map, Set)中equals()和hashCode()方法的作用,建议你看一下这个课程Java基础:集合.
问题13:synchroize getInstance()方法的临界区和synchronize 整个getInstance()方法哪个好?(答案)答: 答案是只synchronize 临界区。因为如果你锁了整个方法,每次调用这个方法,都必须等,即使你并不是在创建对象。