A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© zzy891226 中级黑马   /  2015-7-24 14:15  /  398 人查看  /  7 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

续《常见面试题(一)》网址:  http://bbs.itheima.com/thread-217328-1-1.html

经过一天的休息小编我的心情是十分亢奋,跟打鸡血似的!我用这激情四射的心大家总结一下《常见面试题(二)》,希望对大家有所帮助。如果喜欢小编的就给小编点赞,不喜欢的就给小编拍个赞吧,哈哈哈哈!!!废话不多说,以下是面试总结:

11线程之间通信的理解
其实,Java提供了3个非常重要的方法来巧妙地解决线程间的通信问题。
这3个方法分别是:wait()、notify()和notifyAll()。
它们都是Object类的最终方法,因此每一个类都默认拥有它们。
虽然所有的类都默认拥有这3个方法,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。

这些方法在Object类中声明的语法格式如下所示:
        final void wait() hrows InterruptedException   
        final void notify()
        final void notifyAll()

调用wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒。
调用notify()方法可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行态。
调用notifyAll()方法可以使所有正在等待队列中等待同一共享资源的线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。

显然,利用这些方法就不必再循环检测共享资源的状态,而是在需要的时候直接唤醒等待队列中的线程就可以了。这样不但节省了宝贵的CPU资源,也提高了程序的效率。

由于wait()方法在声明的时候被声明为抛出InterruptedException异常,因此,在调用wait()方法时,需要将它放入try…catch代码块中。此外,使用该方法时还需要把它放到一个同步代码段中,否则会出现如下异常:
"java.lang.IllegalMonitorStateException: current thread not owner"

12线程的状态
线程的五种状态:
1)新建(new) 用new语句创建的线程对处于新建状态,此时它和其它Java对象一样,仅仅在Heap中被分配了内存。当一个线程处于新建状态时,它仅仅是一个空的线程对象,系统不为它分配资源。 Thread t = new Thread(new Runner());
2)就绪(Runnable) 程序通过线程对象调用启动方法start()后,系统会为这个线程分配它运行时所需的除处理器之外的所有系统资源。这时,它处在随时可以运行的状态,在随后的任意时刻,只要它获得处理器即会进入运行状态。 t.start()
3)运行(Running) 处于这个状态的线程占用CPU,执行程序代码。在并发环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。如果计算机中有多个CPU,那么同一时刻可以让几个线程占用不同的CPU,使它们都处于运行状态,只有处于就绪状态的线程才有机会转到运行状态。
4)阻塞(Blocked) 阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态可分为以下3种:
        位于对象等待池中的阻塞状态(Blocked in object's wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中。
        位于对象锁池中的阻塞状态(Blocked in object's lock pool):当线程处于运行状态,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中。
        其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。当一个线程执行System.out.println()或者System.in.read()方法时是,就会发出一个I/O请求,该线程放弃CPU,进入阻塞状态,直到I/O处理完毕,该线程才会恢复执行。
5)死亡(Dead) 当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。线程有可能是正常执行完run()方法而退出,也有可能是遇到异常而退出。不管线程是正常结束还是异常结束,都不会对其他线程造成影响。
 
13 Set、List、Map集合的区别
List:将以特定次序存储元素。所以取出来的顺序可能和放入顺序不同。可重复
        --ArrayList / LinkedList / Vector
Set : Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。
        --HashSet / TreeSet
Map:持有 key-value pair,像个小型数据库。Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
        --HashMap
        --HashTable
        --TreeMap
总结
1)如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。

2)如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。

3)在除需要排序时使用TreeSet,TreeMap外,都应使用HashSet,HashMap,因为他们 的效率更高。

4)要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
 

5)容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。一旦将对象置入容器内,便损失了该对象的型别信息。

6. 尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

注意:
1)Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
2)Set和Collection拥有一模一样的接口。
3)List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)
4)一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
5)Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
      HashMap会利用对象的hashCode来快速找到key。
6)Map中元素,可以将key序列、value序列单独抽取出来。
使用keySet()抽取key序列,将map中的所有keys生成一个Set。
使用values()抽取value序列,将map中的所有values生成一个Collection。
为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。

14 数组和集合的区别
1)数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。
2)数组要声明元素的类型,集合类的元素类型却是object。
3)数组要有整数下标才能访问特定的元素,然而很多时候这样的下标并不是很有用。集合也是数据列表却不使用下标访问。很多时候集合有定制的下标类型,对于队列和栈根本就不支持下标访问!
4)数组不论是效率还是类型检查都是最好的,集合便于使用。
5)数组是一种可读/可写数据结构,没有办法创建一个只读数组。然而可以使用集合中提供的只读方式来实现,该方法将返回一个集合的只读版本。

15、String、StringBuffer和StringBuilder的区别
1)在执行速度方面的比较:StringBuilder >  StringBuffer  
2)StringBuffer与StringBuilder,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度就快了。
3)StringBuilder:线程非安全的,是线程不同步的(JDK1.5后出现)
  StringBuffer:线程安全的,是线程同步的
当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。
对于三者使用的总结:
1)如果要操作少量的数据用 String
2)单线程操作字符串缓冲区 下操作大量数据  StringBuilder
3)多线程操作字符串缓冲区 下操作大量数据  StringBuffer(多线程中通常不建议使用StringBuffer,最好使用StringBuilder然后自己加同步)

小编在发帖的时候遇到了一点小小的意外,导致重新总结了一遍,可能内容没之前版本生动,希望大家多多海涵!!!

评分

参与人数 1黑马币 +6 收起 理由
郝民杰 + 6 很给力!感谢分享!

查看全部评分

7 个回复

倒序浏览
用心的总结,良心之作,感谢作者。
回复 使用道具 举报
用心的总结,良心之作
回复 使用道具 举报
不错不错  虽然没学完 不过先复制下来留着以后看
回复 使用道具 举报
真是不错呢
回复 使用道具 举报
很全面 ,很是感谢
回复 使用道具 举报
不错,虽然看完了所有的基础视频,但是想做出这样的总结还是很有难度。
回复 使用道具 举报
总结不错,多多学习。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马